diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/drivers/media/video/msp3400-old.c | 1947 | ||||
-rw-r--r-- | linux/drivers/media/video/tea5767.c | 37 | ||||
-rw-r--r-- | linux/drivers/media/video/tuner-core.c | 212 | ||||
-rw-r--r-- | linux/drivers/media/video/tuner-simple.c | 4 | ||||
-rw-r--r-- | linux/include/media/tuner.h | 12 |
5 files changed, 109 insertions, 2103 deletions
diff --git a/linux/drivers/media/video/msp3400-old.c b/linux/drivers/media/video/msp3400-old.c deleted file mode 100644 index 63d964bba..000000000 --- a/linux/drivers/media/video/msp3400-old.c +++ /dev/null @@ -1,1947 +0,0 @@ -/* - * programming the msp34* sound processor family - * - * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> - * - * what works and what doesn't: - * - * AM-Mono - * Support for Hauppauge cards added (decoding handled by tuner) added by - * Frederic Crozat <fcrozat@mail.dotcom.fr> - * - * FM-Mono - * should work. The stereo modes are backward compatible to FM-mono, - * therefore FM-Mono should be allways available. - * - * FM-Stereo (B/G, used in germany) - * should work, with autodetect - * - * FM-Stereo (satellite) - * should work, no autodetect (i.e. default is mono, but you can - * switch to stereo -- untested) - * - * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) - * should work, with autodetect. Support for NICAM was added by - * Pekka Pietikainen <pp@netppl.fi> - * - * - * TODO: - * - better SAT support - * - * - * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) - * using soundcore instead of OSS - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/videodev.h> -#include <linux/init.h> -#include <linux/smp_lock.h> -#include <asm/semaphore.h> -#include <asm/pgtable.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#include "audiochip.h" -#include "i2c-compat.h" -#include "id.h" -#else -#include <media/audiochip.h> -#include <media/id.h> -#endif -#include "msp3400.h" -#include "compat.h" - -#define OPMODE_AUTO -1 -#define OPMODE_MANUAL 0 -#define OPMODE_SIMPLE 1 /* use short programming (>= msp3410 only) */ -#define OPMODE_SIMPLER 2 /* use shorter programming (>= msp34xxG) */ - -/* insmod parameters */ -static int opmode = OPMODE_AUTO; -static int debug = 0; /* debug output */ -static int once = 0; /* no continous stereo monitoring */ -static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), - the autoscan seems work well only with FM... */ -static int standard = 1; /* Override auto detect of audio standard, if needed. */ -static int dolby = 0; - -static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual - (msp34xxg only) 0x00a0-0x03c0 */ - -struct msp3400c { - int rev1,rev2; - - int opmode; - int mode; - int norm; - int nicam_on; - int acb; - int main, second; /* sound carrier */ - int input; - int source; /* see msp34xxg_set_source */ - - /* v4l2 */ - int audmode; - int rxsubchans; - - int muted; - int volume, balance; - int bass, treble; - - /* thread */ - pid_t tpid; - struct completion texit; - wait_queue_head_t wq; - - int active:1; - int restart:1; - int rmmod:1; - - int watch_stereo; - struct timer_list wake_stereo; -}; - -#define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00) -#define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@') -#define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@') -#define HAVE_RADIO(msp) ((msp->rev1 & 0xff) >= 'G'-'@') - -#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ - -/* ---------------------------------------------------------------------- */ - -#define dprintk if (debug >= 1) printk -#define d2printk if (debug >= 2) printk - -MODULE_PARM(once,"i"); -MODULE_PARM_DESC(once, "No continuous stereo monitoring"); -MODULE_PARM(debug,"i"); -MODULE_PARM_DESC(debug, "Enable debug messages"); -MODULE_PARM(opmode,"i"); -MODULE_PARM(stereo_threshold,"i"); -MODULE_PARM(standard,"i"); -MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); -MODULE_PARM(amsound,"i"); -MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); -MODULE_PARM(dolby,"i"); - -MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */ - -/* ---------------------------------------------------------------------- */ - -#define I2C_MSP3400C 0x80 -#define I2C_MSP3400C_ALT 0x88 - -#define I2C_MSP3400C_DEM 0x10 -#define I2C_MSP3400C_DFP 0x12 - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { - I2C_MSP3400C >> 1, - I2C_MSP3400C_ALT >> 1, - I2C_CLIENT_END -}; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END}; -#endif -I2C_CLIENT_INSMOD; - -/* ----------------------------------------------------------------------- */ -/* functions for talking to the MSP3400C Sound processor */ - -#ifndef I2C_M_IGNORE_NAK -# define I2C_M_IGNORE_NAK 0x1000 -#endif - -static int msp3400c_reset(struct i2c_client *client) -{ - /* reset and read revision code */ - static char reset_off[3] = { 0x00, 0x80, 0x00 }; - static char reset_on[3] = { 0x00, 0x00, 0x00 }; - static char write[3] = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e }; - char read[2]; - struct i2c_msg reset[2] = { - { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, - { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, - }; - struct i2c_msg test[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read }, - }; - - if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) || - (1 != i2c_transfer(client->adapter,&reset[1],1)) || - (2 != i2c_transfer(client->adapter,test,2)) ) { - printk(KERN_ERR "msp3400: chip reset failed\n"); - return -1; - } - return 0; -} - -static int -msp3400c_read(struct i2c_client *client, int dev, int addr) -{ - int err; - - unsigned char write[3]; - unsigned char read[2]; - struct i2c_msg msgs[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read } - }; - write[0] = dev+1; - write[1] = addr >> 8; - write[2] = addr & 0xff; - - for (err = 0; err < 3;) { - if (2 == i2c_transfer(client->adapter,msgs,2)) - break; - err++; - printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", - err, dev, addr); - msleep(10); - } - if (3 == err) { - printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(client); - return -1; - } - return read[0] << 8 | read[1]; -} - -static int -msp3400c_write(struct i2c_client *client, int dev, int addr, int val) -{ - int err; - unsigned char buffer[5]; - - buffer[0] = dev; - buffer[1] = addr >> 8; - buffer[2] = addr & 0xff; - buffer[3] = val >> 8; - buffer[4] = val & 0xff; - - for (err = 0; err < 3;) { - if (5 == i2c_master_send(client, buffer, 5)) - break; - err++; - printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", - err, dev, addr); - msleep(10); - } - if (3 == err) { - printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(client); - return -1; - } - return 0; -} - -/* ------------------------------------------------------------------------ */ - -/* This macro is allowed for *constants* only, gcc must calculate it - at compile time. Remember -- no floats in kernel mode */ -#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) - -#define MSP_MODE_AM_DETECT 0 -#define MSP_MODE_FM_RADIO 2 -#define MSP_MODE_FM_TERRA 3 -#define MSP_MODE_FM_SAT 4 -#define MSP_MODE_FM_NICAM1 5 -#define MSP_MODE_FM_NICAM2 6 -#define MSP_MODE_AM_NICAM 7 -#define MSP_MODE_BTSC 8 -#define MSP_MODE_EXTERN 9 - -static struct MSP_INIT_DATA_DEM { - int fir1[6]; - int fir2[6]; - int cdo1; - int cdo2; - int ad_cv; - int mode_reg; - int dfp_src; - int dfp_matrix; -} msp_init_data[] = { - /* AM (for carrier detect / msp3400) */ - { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0500, 0x0020, 0x3000}, - - /* AM (for carrier detect / msp3410) */ - { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0100, 0x0020, 0x3000}, - - /* FM Radio */ - { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, - MSP_CARRIER(10.7), MSP_CARRIER(10.7), - 0x00d0, 0x0480, 0x0020, 0x3000 }, - - /* Terrestial FM-mono + FM-stereo */ - { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0480, 0x0030, 0x3000}, - - /* Sat FM-mono */ - { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0480, 0x0000, 0x3000}, - - /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ - { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0040, 0x0120, 0x3000}, - - /* NICAM/FM -- I (6.0/6.552) */ - { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(6.0), MSP_CARRIER(6.0), - 0x00d0, 0x0040, 0x0120, 0x3000}, - - /* NICAM/AM -- L (6.5/5.85) */ - { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0140, 0x0120, 0x7c03}, -}; - -struct CARRIER_DETECT { - int cdo; - char *name; -}; - -static struct CARRIER_DETECT carrier_detect_main[] = { - /* main carrier */ - { MSP_CARRIER(4.5), "4.5 NTSC" }, - { MSP_CARRIER(5.5), "5.5 PAL B/G" }, - { MSP_CARRIER(6.0), "6.0 PAL I" }, - { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } -}; - -static struct CARRIER_DETECT carrier_detect_55[] = { - /* PAL B/G */ - { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, - { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } -}; - -static struct CARRIER_DETECT carrier_detect_65[] = { - /* PAL SAT / SECAM */ - { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, - { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, - { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, - { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, - { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, - { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, -}; - -#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) - -/* ----------------------------------------------------------------------- */ - -static int scarts[3][9] = { - /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ - { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, - { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, - { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, -}; - -static char *scart_names[] = { - "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" -}; - -static void -msp3400c_set_scart(struct i2c_client *client, int in, int out) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - if (-1 == scarts[out][in]) - return; - - dprintk(KERN_DEBUG - "msp34xx: scart switch: %s => %d\n",scart_names[in],out); - msp->acb &= ~scarts[out][SCART_MASK]; - msp->acb |= scarts[out][in]; - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb); -} - -/* ------------------------------------------------------------------------ */ - -static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) -{ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ -} - -static void msp3400c_setvolume(struct i2c_client *client, - int muted, int volume, int balance) -{ - int val = 0, bal = 0; - - if (!muted) { - val = (volume * 0x73 / 65535) << 8; - } - if (val) { - bal = (balance / 256) - 128; - } - dprintk(KERN_DEBUG - "msp34xx: setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n", - muted ? "on" : "off", volume, balance, val>>8, bal); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, - muted ? 0x01 : (val | 0x01)); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, bal << 8); -} - -static void msp3400c_setbass(struct i2c_client *client, int bass) -{ - int val = ((bass-32768) * 0x60 / 65535) << 8; - - dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ -} - -static void msp3400c_settreble(struct i2c_client *client, int treble) -{ - int val = ((treble-32768) * 0x60 / 65535) << 8; - - dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ -} - -static void msp3400c_setmode(struct i2c_client *client, int type) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - int i; - - dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type); - msp->mode = type; - msp->audmode = V4L2_TUNER_MODE_MONO; - msp->rxsubchans = V4L2_TUNER_SUB_MONO; - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ - msp_init_data[type].ad_cv); - - for (i = 5; i >= 0; i--) /* fir 1 */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, - msp_init_data[type].fir1[i]); - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); - for (i = 5; i >= 0; i--) - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, - msp_init_data[type].fir2[i]); - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ - msp_init_data[type].mode_reg); - - msp3400c_setcarrier(client, msp_init_data[type].cdo1, - msp_init_data[type].cdo2); - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ - - if (dolby) { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, - 0x0520); /* I2S1 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, - 0x0620); /* I2S2 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, - msp_init_data[type].dfp_src); - } else { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, - msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, - msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, - msp_init_data[type].dfp_src); - } - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, - msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, - msp_init_data[type].dfp_matrix); - - if (HAVE_NICAM(msp)) { - /* nicam prescale */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ - } -} - -static int best_audio_mode(int rxsubchans) -{ - if (rxsubchans & V4L2_TUNER_SUB_STEREO) - return V4L2_TUNER_MODE_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG1) - return V4L2_TUNER_MODE_LANG1; - if (rxsubchans & V4L2_TUNER_SUB_LANG2) - return V4L2_TUNER_MODE_LANG2; - return V4L2_TUNER_MODE_MONO; -} - -/* turn on/off nicam + stereo */ -static void msp3400c_set_audmode(struct i2c_client *client, int audmode) -{ - static char *strmode[16] = { -#if __GNUC__ >= 3 - [ 0 ... 15 ] = "invalid", -#endif - [ V4L2_TUNER_MODE_MONO ] = "mono", - [ V4L2_TUNER_MODE_STEREO ] = "stereo", - [ V4L2_TUNER_MODE_LANG1 ] = "lang1", - [ V4L2_TUNER_MODE_LANG2 ] = "lang2", - }; - struct msp3400c *msp = i2c_get_clientdata(client); - int nicam=0; /* channel source: FM/AM or nicam */ - int src=0; - - BUG_ON(msp->opmode == OPMODE_SIMPLER); - msp->audmode = audmode; - - /* switch demodulator */ - switch (msp->mode) { - case MSP_MODE_FM_TERRA: - dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n", - strmode[audmode]); - msp3400c_setcarrier(client,msp->second,msp->main); - switch (audmode) { - case V4L2_TUNER_MODE_STEREO: - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); - break; - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - case V4L2_TUNER_MODE_LANG2: - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); - break; - } - break; - case MSP_MODE_FM_SAT: - dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n", - strmode[audmode]); - switch (audmode) { - case V4L2_TUNER_MODE_MONO: - msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); - break; - case V4L2_TUNER_MODE_STEREO: - msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); - break; - case V4L2_TUNER_MODE_LANG1: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - case V4L2_TUNER_MODE_LANG2: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - } - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n", - strmode[audmode]); - msp3400c_setcarrier(client,msp->second,msp->main); - if (msp->nicam_on) - nicam=0x0100; - break; - case MSP_MODE_BTSC: - dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n", - strmode[audmode]); - nicam=0x0300; - break; - case MSP_MODE_EXTERN: - dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n", - strmode[audmode]); - nicam = 0x0200; - break; - case MSP_MODE_FM_RADIO: - dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n", - strmode[audmode]); - break; - default: - dprintk(KERN_DEBUG "msp3400: mono setstereo\n"); - return; - } - - /* switch audio */ - switch (audmode) { - case V4L2_TUNER_MODE_STEREO: - src = 0x0020 | nicam; -#if 0 - /* spatial effect */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); -#endif - break; - case V4L2_TUNER_MODE_MONO: - if (msp->mode == MSP_MODE_AM_NICAM) { - dprintk("msp3400: switching to AM mono\n"); - /* AM mono decoding is handled by tuner, not MSP chip */ - /* SCART switching control register */ - msp3400c_set_scart(client,SCART_MONO,0); - src = 0x0200; - break; - } - case V4L2_TUNER_MODE_LANG1: - src = 0x0000 | nicam; - break; - case V4L2_TUNER_MODE_LANG2: - src = 0x0010 | nicam; - break; - } - dprintk(KERN_DEBUG - "msp3400: setstereo final source/matrix = 0x%x\n", src); - - if (dolby) { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); - } else { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); - } -} - -static void -msp3400c_print_mode(struct msp3400c *msp) -{ - if (msp->main == msp->second) { - printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n", - msp->main/910000,(msp->main/910)%1000); - } else { - printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n", - msp->main/910000,(msp->main/910)%1000); - } - if (msp->mode == MSP_MODE_FM_NICAM1 || - msp->mode == MSP_MODE_FM_NICAM2) - printk(KERN_DEBUG "msp3400: NICAM/FM carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - if (msp->mode == MSP_MODE_AM_NICAM) - printk(KERN_DEBUG "msp3400: NICAM/AM carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - if (msp->mode == MSP_MODE_FM_TERRA && - msp->main != msp->second) { - printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - } -} - -/* ----------------------------------------------------------------------- */ - -struct REGISTER_DUMP { - int addr; - char *name; -}; - -struct REGISTER_DUMP d1[] = { - { 0x007e, "autodetect" }, - { 0x0023, "C_AD_BITS " }, - { 0x0038, "ADD_BITS " }, - { 0x003e, "CIB_BITS " }, - { 0x0057, "ERROR_RATE" }, -}; - -static int -autodetect_stereo(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - int val; - int rxsubchans = msp->rxsubchans; - int newnicam = msp->nicam_on; - int update = 0; - - switch (msp->mode) { - case MSP_MODE_FM_TERRA: - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); - if (val > 32767) - val -= 65536; - dprintk(KERN_DEBUG - "msp34xx: stereo detect register: %d\n",val); - if (val > 4096) { - rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - } else if (val < -4096) { - rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - } else { - rxsubchans = V4L2_TUNER_SUB_MONO; - } - newnicam = 0; - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); - dprintk(KERN_DEBUG - "msp34xx: nicam sync=%d, mode=%d\n", - val & 1, (val & 0x1e) >> 1); - - if (val & 1) { - /* nicam synced */ - switch ((val & 0x1e) >> 1) { - case 0: - case 8: - rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 1: - case 9: - rxsubchans = V4L2_TUNER_SUB_MONO - | V4L2_TUNER_SUB_LANG1; - break; - case 2: - case 10: - rxsubchans = V4L2_TUNER_SUB_MONO - | V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; - break; - default: - rxsubchans = V4L2_TUNER_SUB_MONO; - break; - } - newnicam=1; - } else { - newnicam = 0; - rxsubchans = V4L2_TUNER_SUB_MONO; - } - break; - case MSP_MODE_BTSC: - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); - dprintk(KERN_DEBUG - "msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", - val, - (val & 0x0002) ? "no" : "yes", - (val & 0x0004) ? "no" : "yes", - (val & 0x0040) ? "stereo" : "mono", - (val & 0x0080) ? ", nicam 2nd mono" : "", - (val & 0x0100) ? ", bilingual/SAP" : ""); - rxsubchans = V4L2_TUNER_SUB_MONO; - if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO; - if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; - break; - } - if (rxsubchans != msp->rxsubchans) { - update = 1; - dprintk(KERN_DEBUG "msp34xx: watch: rxsubchans %d => %d\n", - msp->rxsubchans,rxsubchans); - msp->rxsubchans = rxsubchans; - } - if (newnicam != msp->nicam_on) { - update = 1; - dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n", - msp->nicam_on,newnicam); - msp->nicam_on = newnicam; - } - return update; -} - -/* - * A kernel thread for msp3400 control -- we don't want to block the - * in the ioctl while doing the sound carrier & stereo detect - */ - -static int msp34xx_sleep(struct msp3400c *msp, int timeout) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&msp->wq, &wait); - if (!msp->rmmod) { - if (timeout < 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } else - msleep_interruptible(timeout); - } - remove_wait_queue(&msp->wq, &wait); - return msp->rmmod || signal_pending(current); -} - -static void msp3400c_stereo_wake(unsigned long data) -{ - struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */ - - wake_up_interruptible(&msp->wq); -} - -/* stereo/multilang monitoring */ -static void watch_stereo(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - if (autodetect_stereo(client)) - msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans)); - if (once) - msp->watch_stereo = 0; - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+5*HZ); -} - -static int msp3400c_thread(void *data) -{ - struct i2c_client *client = data; - struct msp3400c *msp = i2c_get_clientdata(client); - - struct CARRIER_DETECT *cd; - int count, max1,max2,val1,val2, val,this; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) - lock_kernel(); - daemonize(); - sigfillset(¤t->blocked); - strcpy(current->comm,"msp3400"); - unlock_kernel(); -#else - daemonize("msp3400"); - allow_signal(SIGTERM); -#endif - printk("msp3400: daemon started\n"); - - for (;;) { - d2printk("msp3400: thread: sleep\n"); - if (msp34xx_sleep(msp,-1)) - goto done; - - d2printk("msp3400: thread: wakeup\n"); - msp->active = 1; - - if (msp->watch_stereo) { - watch_stereo(client); - msp->active = 0; - continue; - } - - /* some time for the tuner to sync */ - if (msp34xx_sleep(msp,200)) - goto done; - - restart: - if (VIDEO_MODE_RADIO == msp->norm || - MSP_MODE_EXTERN == msp->mode) { - /* no carrier scan, just unmute */ - printk("msp3400: thread: no carrier scan\n"); - msp3400c_setvolume(client, msp->muted, - msp->volume, msp->balance); - continue; - } - msp->restart = 0; - msp3400c_setvolume(client, msp->muted, 0, 0); - msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); - val1 = val2 = 0; - max1 = max2 = -1; - del_timer(&msp->wake_stereo); - msp->watch_stereo = 0; - - /* carrier detect pass #1 -- main carrier */ - cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); - - if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { - /* autodetect doesn't work well with AM ... */ - max1 = 3; - count = 0; - dprintk("msp3400: AM sound override\n"); - } - - for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - - if (msp34xx_sleep(msp,100)) - goto done; - if (msp->restart) - msp->restart = 0; - - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32767) - val -= 65536; - if (val1 < val) - val1 = val, max1 = this; - dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); - } - - /* carrier detect pass #2 -- second (stereo) carrier */ - switch (max1) { - case 1: /* 5.5 */ - cd = carrier_detect_55; - count = CARRIER_COUNT(carrier_detect_55); - break; - case 3: /* 6.5 */ - cd = carrier_detect_65; - count = CARRIER_COUNT(carrier_detect_65); - break; - case 0: /* 4.5 */ - case 2: /* 6.0 */ - default: - cd = NULL; count = 0; - break; - } - - if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { - /* autodetect doesn't work well with AM ... */ - cd = NULL; count = 0; max2 = 0; - } - for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - - if (msp34xx_sleep(msp,100)) - goto done; - if (msp->restart) - goto restart; - - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32767) - val -= 65536; - if (val2 < val) - val2 = val, max2 = this; - dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); - } - - /* programm the msp3400 according to the results */ - msp->main = carrier_detect_main[max1].cdo; - switch (max1) { - case 1: /* 5.5 */ - if (max2 == 0) { - /* B/G FM-stereo */ - msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); - msp->watch_stereo = 1; - } else if (max2 == 1 && HAVE_NICAM(msp)) { - /* B/G NICAM */ - msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 2: /* 6.0 */ - /* PAL I NICAM */ - msp->second = MSP_CARRIER(6.552); - msp3400c_setmode(client, MSP_MODE_FM_NICAM2); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - break; - case 3: /* 6.5 */ - if (max2 == 1 || max2 == 2) { - /* D/K FM-stereo */ - msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); - msp->watch_stereo = 1; - } else if (max2 == 0 && - msp->norm == VIDEO_MODE_SECAM) { - /* L NICAM or AM-mono */ - msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_AM_NICAM); - msp->nicam_on = 0; - msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); - msp3400c_setcarrier(client, msp->second, msp->main); - /* volume prescale for SCART (AM mono input) */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); - msp->watch_stereo = 1; - } else if (max2 == 0 && HAVE_NICAM(msp)) { - /* D/K NICAM */ - msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 0: /* 4.5 */ - default: - no_second: - msp->second = carrier_detect_main[max1].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->rxsubchans = V4L2_TUNER_SUB_MONO; - msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO); - break; - } - - /* unmute + restore dfp registers */ - msp3400c_setvolume(client, msp->muted, - msp->volume, msp->balance); - - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+5*HZ); - - if (debug) - msp3400c_print_mode(msp); - - msp->active = 0; - } - -done: - msp->active = 0; - dprintk(KERN_DEBUG "msp3400: thread: exit\n"); - complete_and_exit(&msp->texit, 0); -} - -/* ----------------------------------------------------------------------- */ -/* this one uses the automatic sound standard detection of newer */ -/* msp34xx chip versions */ - -static struct MODES { - int retval; - int main, second; - char *name; -} modelist[] = { - { 0x0000, 0, 0, "ERROR" }, - { 0x0001, 0, 0, "autodetect start" }, - { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, - { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, - { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, - { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, - { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, - { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, - { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, - { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, - { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, - { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, - { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, - { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, - { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, - { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, - { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, - { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, - { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, - { -1, 0, 0, NULL }, /* EOF */ -}; - -static inline const char *msp34xx_standard_mode_name(int mode) -{ - int i; - for (i = 0; modelist[i].name != NULL; i++) - if (modelist[i].retval == mode) - return modelist[i].name; - return "unknown"; -} - -static int msp34xx_modus(int norm) -{ - switch (norm) { - case VIDEO_MODE_PAL: - return 0x1003; - case VIDEO_MODE_NTSC: /* BTSC */ - return 0x2003; - case VIDEO_MODE_SECAM: - return 0x0003; - case VIDEO_MODE_RADIO: - return 0x0003; - case VIDEO_MODE_AUTO: - return 0x2003; - default: - return 0x0003; - } -} - -static int msp34xx_standard(int norm) -{ - switch (norm) { - case VIDEO_MODE_PAL: - return 1; - case VIDEO_MODE_NTSC: /* BTSC */ - return 0x0020; - case VIDEO_MODE_SECAM: - return 1; - case VIDEO_MODE_RADIO: - return 0x0040; - default: - return 1; - } -} - -static int msp3410d_thread(void *data) -{ - struct i2c_client *client = data; - struct msp3400c *msp = i2c_get_clientdata(client); - int mode,val,i,std; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) - lock_kernel(); - daemonize(); - sigfillset(¤t->blocked); - strcpy(current->comm,"msp3410 [auto]"); - unlock_kernel(); -#else - daemonize("msp3410 [auto]"); - allow_signal(SIGTERM); -#endif - printk("msp3410: daemon started\n"); - - for (;;) { - d2printk(KERN_DEBUG "msp3410: thread: sleep\n"); - if (msp34xx_sleep(msp,-1)) - goto done; - - d2printk(KERN_DEBUG "msp3410: thread: wakeup\n"); - msp->active = 1; - - if (msp->watch_stereo) { - watch_stereo(client); - msp->active = 0; - continue; - } - - /* some time for the tuner to sync */ - if (msp34xx_sleep(msp,200)) - goto done; - - restart: - if (msp->mode == MSP_MODE_EXTERN) { - /* no carrier scan needed, just unmute */ - dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n"); - msp3400c_setvolume(client, msp->muted, - msp->volume, msp->balance); - continue; - } - msp->restart = 0; - del_timer(&msp->wake_stereo); - msp->watch_stereo = 0; - - /* put into sane state (and mute) */ - msp3400c_reset(client); - - /* start autodetect */ - mode = msp34xx_modus(msp->norm); - std = msp34xx_standard(msp->norm); - msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); - - if (debug) - printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n", - msp34xx_standard_mode_name(std) ,std); - - if (std != 1) { - /* programmed some specific mode */ - val = std; - } else { - /* triggered autodetect */ - for (;;) { - if (msp34xx_sleep(msp,100)) - goto done; - if (msp->restart) - goto restart; - - /* check results */ - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); - if (val < 0x07ff) - break; - dprintk(KERN_DEBUG "msp3410: detection still in progress\n"); - } - } - for (i = 0; modelist[i].name != NULL; i++) - if (modelist[i].retval == val) - break; - dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown", - val); - msp->main = modelist[i].main; - msp->second = modelist[i].second; - - if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { - /* autodetection has failed, let backup */ - dprintk(KERN_DEBUG "msp3410: autodetection failed," - " switching to backup mode: %s (0x%04x)\n", - modelist[8].name ? modelist[8].name : "unknown",val); - val = 0x0009; - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); - } - - /* set various prescales */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */ - - /* set stereo */ - switch (val) { - case 0x0008: /* B/G NICAM */ - case 0x000a: /* I NICAM */ - if (val == 0x0008) - msp->mode = MSP_MODE_FM_NICAM1; - else - msp->mode = MSP_MODE_FM_NICAM2; - /* just turn on stereo */ - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->nicam_on = 1; - msp->watch_stereo = 1; - msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO); - break; - case 0x0009: - msp->mode = MSP_MODE_AM_NICAM; - msp->rxsubchans = V4L2_TUNER_SUB_MONO; - msp->nicam_on = 1; - msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO); - msp->watch_stereo = 1; - break; - case 0x0020: /* BTSC */ - /* just turn on stereo */ - msp->mode = MSP_MODE_BTSC; - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->nicam_on = 0; - msp->watch_stereo = 1; - msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO); - break; - case 0x0040: /* FM radio */ - msp->mode = MSP_MODE_FM_RADIO; - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->audmode = V4L2_TUNER_MODE_STEREO; - msp->nicam_on = 0; - msp->watch_stereo = 0; - /* not needed in theory if HAVE_RADIO(), but - short programming enables carrier mute */ - msp3400c_setmode(client,MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - /* scart routing */ - msp3400c_set_scart(client,SCART_IN2,0); -#if 0 - /* radio from SCART_IN2 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220); -#else - /* msp34xx does radio decoding */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020); -#endif - break; - case 0x0003: - case 0x0004: - case 0x0005: - msp->mode = MSP_MODE_FM_TERRA; - msp->rxsubchans = V4L2_TUNER_SUB_MONO; - msp->audmode = V4L2_TUNER_MODE_MONO; - msp->nicam_on = 0; - msp->watch_stereo = 1; - break; - } - - /* unmute, restore misc registers */ - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->muted, - msp->volume, msp->balance); - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb); - - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+HZ); - - msp->active = 0; - } - -done: - msp->active = 0; - dprintk(KERN_DEBUG "msp3410: thread: exit\n"); - complete_and_exit(&msp->texit, 0); - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* msp34xxG + (simpler no-thread) */ -/* this one uses both automatic standard detection and automatic sound */ -/* select which are available in the newer G versions */ -/* struct msp: only norm, acb and source are really used in this mode */ - -static void msp34xxg_set_source(struct i2c_client *client, int source); - -/* (re-)initialize the msp34xxg, according to the current norm in msp->norm - * return 0 if it worked, -1 if it failed - */ -static int msp34xxg_reset(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - int i; - int modus; - int std; - - if (msp3400c_reset(client)) - return -1; - - /* make sure that input/output is muted (paranoid mode) */ - if (msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x13, /* ACB */ - 0x0f20 /* mute DSP input, mute SCART 1 */)) - return -1; - - /* step-by-step initialisation, as described in the manual */ - modus = msp34xx_modus(msp->norm); - modus &= ~0x03; /* STATUS_CHANGE=0 */ - modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */ - if (msp3400c_write(client, - I2C_MSP3400C_DEM, - 0x30/*MODUS*/, - modus)) - return -1; - - /* write the dfps that may have an influence on - standard/audio autodetection right now */ - msp34xxg_set_source(client, msp->source); - - if (msp3400c_write(client, I2C_MSP3400C_DFP, - 0x0e, /* AM/FM Prescale */ - 0x3000 /* default: [15:8] 75khz deviation */)) - return -1; - - if (msp3400c_write(client, I2C_MSP3400C_DFP, - 0x10, /* NICAM Prescale */ - 0x5a00 /* default: 9db gain (as recommended) */)) - return -1; - - std = standard; - if (msp3400c_write(client, - I2C_MSP3400C_DEM, - 0x20, /* STANDARD SELECT */ - std /* default: 0x01 for automatic standard select*/)) - return -1; - - - if (std == 0x01) { - dprintk("msp34xxg: triggered autodetect, waiting for result\n"); - - /* triggered autodetect */ - for (i = 0; i < 10; i++) { - int val; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - if (signal_pending(current)) - return -1; /* failed */ - - /* check results */ - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); - if (val < 0x07ff) { - std=val; - break; - } - dprintk("msp34xxg: detection still in progress\n"); - } - if (i == 10) { - dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n"); - return -1; - } - } - dprintk("msp34xxg: current mode: %s (0x%04x)\n", - msp34xx_standard_mode_name(std), std); - - /* unmute: dispatch sound to scart output, set scart volume */ - dprintk("msp34xxg: unmute\n"); - - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance); - - /* restore ACB */ - if (msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x13, /* ACB */ - msp->acb)) - return -1; - - return 0; -} - -/* set the same 'source' for the loudspeaker, scart and quasi-peak detector - * the value for source is the same as bit 15:8 of DFP registers 0x08, - * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B - * - * this function replaces msp3400c_setstereo - */ -static void msp34xxg_set_source(struct i2c_client *client, int source) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - /* fix matrix mode to stereo and let the msp choose what - * to output according to 'source', as recommended - */ - int value = (source&0x07)<<8|(source==0 ? 0x00:0x20); - dprintk("msp34xxg: set source to %d (0x%x)\n", source, value); - msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x08, /* Loudspeaker Output */ - value); - msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x0a, /* SCART1 DA Output */ - value); - msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x0c, /* Quasi-peak detector */ - value); - /* - * set identification threshold. Personally, I - * I set it to a higher value that the default - * of 0x190 to ignore noisy stereo signals. - * this needs tuning. (recommended range 0x00a0-0x03c0) - * 0x7f0 = forced mono mode - */ - msp3400c_write(client, - I2C_MSP3400C_DEM, - 0x22, /* a2 threshold for stereo/bilingual */ - source==0 ? 0x7f0:stereo_threshold); - msp->source=source; -} - -static void msp34xxg_detect_stereo(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - int status = msp3400c_read(client, - I2C_MSP3400C_DEM, - 0x0200 /* STATUS */); - int is_bilingual = status&0x100; - int is_stereo = status&0x40; - - msp->rxsubchans = 0; - if (is_stereo) - msp->rxsubchans |= V4L2_TUNER_SUB_STEREO; - else - msp->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (is_bilingual) { - msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2; - /* I'm supposed to check whether it's SAP or not - * and set only LANG2/SAP in this case. Yet, the MSP - * does a lot of work to hide this and handle everything - * the same way. I don't want to work around it so unless - * this is a problem, I'll handle SAP just like lang1/lang2. - */ - } - dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", - status, is_stereo, is_bilingual, msp->rxsubchans); -} - -static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - int source = 0; - - switch (audmode) { - case V4L2_TUNER_MODE_MONO: - source=0; /* mono only */ - break; - case V4L2_TUNER_MODE_STEREO: - source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ - /* problem: that could also mean 2 (scart input) */ - break; - case V4L2_TUNER_MODE_LANG1: - source=3; /* stereo or A */ - break; - case V4L2_TUNER_MODE_LANG2: - source=4; /* stereo or B */ - break; - default: /* doing nothing: a safe, sane default */ - audmode = 0; - return; - } - msp->audmode = audmode; - msp34xxg_set_source(client, source); -} - - -/* ----------------------------------------------------------------------- */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -static int msp_attach(struct i2c_adapter *adap, int addr, int kind); -#else -static int msp_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind); -#endif -static int msp_detach(struct i2c_client *client); -static int msp_probe(struct i2c_adapter *adap); -static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); - -static struct i2c_driver driver = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - .owner = THIS_MODULE, -#endif - .name = "i2c msp3400 driver", - .id = I2C_DRIVERID_MSP3400, - .flags = I2C_DF_NOTIFY, - .attach_adapter = msp_probe, - .detach_client = msp_detach, - .command = msp_command, -}; - -static struct i2c_client client_template = -{ - I2C_DEVNAME("(unset)"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -static int msp_attach(struct i2c_adapter *adap, int addr, int kind) -#else -static int msp_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -#endif -{ - struct msp3400c *msp; - struct i2c_client *c; - int (*thread_func)(void *data) = NULL; - - client_template.adapter = adap; - client_template.addr = addr; - - if (-1 == msp3400c_reset(&client_template)) { - dprintk("msp3400: no chip found\n"); - return -1; - } - - if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) - return -ENOMEM; - memcpy(c,&client_template,sizeof(struct i2c_client)); - if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { - kfree(c); - return -ENOMEM; - } - - memset(msp,0,sizeof(struct msp3400c)); - msp->volume = 58880; /* 0db gain */ - msp->balance = 32768; - msp->bass = 32768; - msp->treble = 32768; - msp->input = -1; - msp->muted = 1; - - i2c_set_clientdata(c, msp); - init_waitqueue_head(&msp->wq); - - if (-1 == msp3400c_reset(c)) { - kfree(msp); - kfree(c); - dprintk("msp3400: no chip found\n"); - return -1; - } - - msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e); - if (-1 != msp->rev1) - msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f); - if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { - kfree(msp); - kfree(c); - printk("msp3400: error while reading chip version\n"); - return -1; - } - -#if 0 - /* this will turn on a 1kHz beep - might be useful for debugging... */ - msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040); -#endif - msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance); - - snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d", - (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@', - ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f); - - msp->opmode = opmode; - if (OPMODE_AUTO == msp->opmode) { - if (HAVE_SIMPLER(msp)) - msp->opmode = OPMODE_SIMPLER; - else if (HAVE_SIMPLE(msp)) - msp->opmode = OPMODE_SIMPLE; - else - msp->opmode = OPMODE_MANUAL; - } - - /* timer for stereo checking */ - init_timer(&msp->wake_stereo); - msp->wake_stereo.function = msp3400c_stereo_wake; - msp->wake_stereo.data = (unsigned long)msp; - - /* hello world :-) */ - printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c)); - if (HAVE_NICAM(msp)) - printk(" +nicam"); - if (HAVE_SIMPLE(msp)) - printk(" +simple"); - if (HAVE_SIMPLER(msp)) - printk(" +simpler"); - if (HAVE_RADIO(msp)) - printk(" +radio"); - - /* version-specific initialization */ - switch (msp->opmode) { - case OPMODE_MANUAL: - printk(" mode=manual"); - thread_func = msp3400c_thread; - break; - case OPMODE_SIMPLE: - printk(" mode=simple"); - thread_func = msp3410d_thread; - break; - case OPMODE_SIMPLER: - printk(" mode=simpler"); - msp34xxg_reset(c); - break; - } - printk("\n"); - - /* startup control thread if needed */ - if (thread_func) { - init_completion(&msp->texit); - msp->tpid = kernel_thread(thread_func, (void *)c, 0); - if (msp->tpid < 0) - printk(KERN_WARNING "msp34xx: kernel_thread() failed\n"); - wake_up_interruptible(&msp->wq); - } else { - msp->tpid = -1; - } - - /* done */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - MOD_INC_USE_COUNT; -#endif - i2c_attach_client(c); - return 0; -} - -static int msp_detach(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - /* shutdown control thread */ - del_timer_sync(&msp->wake_stereo); - if (msp->tpid >= 0) { - msp->rmmod = 1; - wake_up_interruptible(&msp->wq); - wait_for_completion(&msp->texit); - } - msp3400c_reset(client); - - i2c_detach_client(client); - kfree(msp); - kfree(client); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - MOD_DEC_USE_COUNT; -#endif - return 0; -} - -static int msp_probe(struct i2c_adapter *adap) -{ -#ifdef I2C_CLASS_TV_ANALOG - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, msp_attach); -#else - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3: - case I2C_ALGO_BIT | I2C_HW_B_BT848: - //case I2C_ALGO_SAA7134: - return i2c_probe(adap, &addr_data, msp_attach); - break; - } -#endif - return 0; -} - -static void msp_wake_thread(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - if (-1 == msp->tpid) - return; - msp3400c_setvolume(client,msp->muted,0,0); - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - if (msp->active) - msp->restart = 1; - wake_up_interruptible(&msp->wq); -} - -/* ----------------------------------------------------------------------- */ - -static int mode_v4l2_to_v4l1(int rxsubchans) -{ - int mode = 0; - - if (rxsubchans & V4L2_TUNER_SUB_STEREO) - mode |= VIDEO_SOUND_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG2) - mode |= VIDEO_SOUND_LANG2; - if (rxsubchans & V4L2_TUNER_SUB_LANG1) - mode |= VIDEO_SOUND_LANG1; - if (0 == mode) - mode |= VIDEO_SOUND_MONO; - return mode; -} - -static int mode_v4l1_to_v4l2(int mode) -{ - if (mode & VIDEO_SOUND_STEREO) - return V4L2_TUNER_MODE_STEREO; - if (mode & VIDEO_SOUND_LANG2) - return V4L2_TUNER_MODE_LANG2; - if (mode & VIDEO_SOUND_LANG1) - return V4L2_TUNER_MODE_LANG1; - return V4L2_TUNER_MODE_MONO; -} - -static void msp_any_rescan(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - switch (msp->opmode) { - case OPMODE_MANUAL: - case OPMODE_SIMPLE: - msp_wake_thread(client); - break; - case OPMODE_SIMPLER: - msp34xxg_reset(client); - break; - } -} - -static void msp_any_detect_stereo(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - switch (msp->opmode) { - case OPMODE_MANUAL: - case OPMODE_SIMPLE: - autodetect_stereo(client); - break; - case OPMODE_SIMPLER: - msp34xxg_detect_stereo(client); - break; - } -} - -static void msp_any_set_audmode(struct i2c_client *client, int audmode) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - switch (msp->opmode) { - case OPMODE_MANUAL: - case OPMODE_SIMPLE: - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - msp3400c_set_audmode(client, audmode); - break; - case OPMODE_SIMPLER: - msp34xxg_set_audmode(client, audmode); - break; - } -} - -static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - __u16 *sarg = arg; - int scart = 0; - - switch (cmd) { - - case AUDC_SET_INPUT: - dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg); - if (*sarg == msp->input) - break; - msp->input = *sarg; - switch (*sarg) { - case AUDIO_RADIO: - /* Hauppauge uses IN2 for the radio */ - msp->mode = MSP_MODE_FM_RADIO; - scart = SCART_IN2; - break; - case AUDIO_EXTERN_1: - /* IN1 is often used for external input ... */ - msp->mode = MSP_MODE_EXTERN; - scart = SCART_IN1; - break; - case AUDIO_EXTERN_2: - /* ... sometimes it is IN2 through ;) */ - msp->mode = MSP_MODE_EXTERN; - scart = SCART_IN2; - break; - case AUDIO_TUNER: - msp->mode = -1; - msp_wake_thread(client); - break; - default: - if (*sarg & AUDIO_MUTE) - msp3400c_set_scart(client,SCART_MUTE,0); - break; - } - if (scart) { - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->audmode = V4L2_TUNER_MODE_STEREO; - msp3400c_set_scart(client,scart,0); - msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900); - if (msp->opmode != OPMODE_SIMPLER) - msp3400c_set_audmode(client, msp->audmode); - } - if (msp->active) - msp->restart = 1; - break; - - case AUDC_SET_RADIO: - dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n"); - msp->norm = VIDEO_MODE_RADIO; - dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n"); - msp->watch_stereo = 0; - del_timer(&msp->wake_stereo); - switch (msp->opmode) { - case OPMODE_MANUAL: - /* set msp3400 to FM radio mode */ - msp3400c_setmode(client,MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - msp3400c_setvolume(client, msp->muted, - msp->volume, msp->balance); - break; - case OPMODE_SIMPLE: - /* the thread will do for us */ - msp_wake_thread(client); - break; - case OPMODE_SIMPLER: - msp34xxg_reset(client); - break; - } - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n"); - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE | - VIDEO_AUDIO_MUTABLE; - if (msp->muted) - va->flags |= VIDEO_AUDIO_MUTE; - - va->volume = msp->volume; - va->balance = (va->volume) ? msp->balance : 32768; - va->bass = msp->bass; - va->treble = msp->treble; - - msp_any_detect_stereo(client); - va->mode = mode_v4l2_to_v4l1(msp->rxsubchans); - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - - dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n"); - msp->muted = (va->flags & VIDEO_AUDIO_MUTE); - msp->volume = va->volume; - msp->balance = va->balance; - msp->bass = va->bass; - msp->treble = va->treble; - - msp3400c_setvolume(client, msp->muted, - msp->volume, msp->balance); - msp3400c_setbass(client,msp->bass); - msp3400c_settreble(client,msp->treble); - - if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO) - msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode)); - break; - } - case VIDIOCSCHAN: - { - struct video_channel *vc = arg; - - dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm); - msp->norm = vc->norm; - msp_any_rescan(client); - break; - } - - case VIDIOCSFREQ: - case VIDIOC_S_FREQUENCY: - { - /* new channel -- kick audio carrier scan */ - dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n"); - msp_any_rescan(client); - break; - } - - /* --- v4l2 ioctls --- */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *vt = arg; - - msp_any_detect_stereo(client); - vt->audmode = msp->audmode; - vt->rxsubchans = msp->rxsubchans; - vt->capability = V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1| - V4L2_TUNER_CAP_LANG2; - break; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; - - /* only set audmode */ - if (vt->audmode != -1 && - vt->audmode != 0) { - msp_any_set_audmode(client, vt->audmode); - } - break; - } - - /* msp34xx specific */ - case MSP_SET_MATRIX: - { - struct msp_matrix *mspm = arg; - - dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n"); - msp3400c_set_scart(client, mspm->input, mspm->output); - break; - } - - default: - /* nothing */ - break; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int __init msp3400_init_module(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit msp3400_cleanup_module(void) -{ - i2c_del_driver(&driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/linux/drivers/media/video/tea5767.c b/linux/drivers/media/video/tea5767.c index df2cb9ed9..38061f94e 100644 --- a/linux/drivers/media/video/tea5767.c +++ b/linux/drivers/media/video/tea5767.c @@ -2,7 +2,7 @@ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview * I2C address is allways 0xC0. * - * $Id: tea5767.c,v 1.14 2005/06/30 16:37:17 mchehab Exp $ + * $Id: tea5767.c,v 1.15 2005/07/02 14:53:02 nsh Exp $ * * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) * This code is placed under the terms of the GNU General Public License @@ -11,28 +11,11 @@ * from their contributions on DScaler. */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/videodev.h> #include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#include "tuner.h" -#include "i2c-compat.h" -#else +#include <linux/videodev.h> +#include <linux/delay.h> +#include <media/tuner.h> #include <media/tuner.h> -#endif - -/* Declared at tuner-core.c */ -extern unsigned int tuner_debug; #define PREFIX "TEA5767 " @@ -135,6 +118,14 @@ extern unsigned int tuner_debug; /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff +enum tea5767_xtal_freq { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + + /*****************************************************************************/ static void set_tv_freq(struct i2c_client *c, unsigned int freq) @@ -344,8 +335,8 @@ int tea5767_tuner_init(struct i2c_client *c) if (tea5767_autodetection(c) == EINVAL) return EINVAL; - tuner_info("type set to %d (%s)\n", t->type, TEA5767_TUNER_NAME); - strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name)); + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); + strlcpy(c->name, "tea5767", sizeof(c->name)); t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index 69e7784c1..13e78f56c 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-core.c,v 1.41 2005/07/01 21:41:37 mchehab Exp $ + * $Id: tuner-core.c,v 1.42 2005/07/02 14:53:02 nsh Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -78,11 +78,11 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); if (t->type == UNSET) { - tuner_info("tuner type not set\n"); + tuner_warn ("tuner type not set\n"); return; } if (NULL == t->tv_freq) { - tuner_info("Huh? tv_set is NULL?\n"); + tuner_warn ("Tuner has no way to set tv freq\n"); return; } if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { @@ -98,24 +98,20 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); if (t->type == UNSET) { - tuner_info("tuner type not set\n"); + tuner_warn ("tuner type not set\n"); return; } if (NULL == t->radio_freq) { - tuner_info("no radio tuning for this one, sorry.\n"); + tuner_warn ("tuner has no way to set radio frequency\n"); return; } - if (freq >= radio_range[0] * 16000 && freq <= radio_range[1] * 16000) { - if (tuner_debug) - tuner_info("radio freq step 62.5Hz (%d.%06d)\n", - freq / 16000, freq % 16000 * 1000 / 16); - t->radio_freq(c, freq); - } else { - tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", + if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) { + tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", freq / 16000, freq % 16000 * 100 / 16000, radio_range[0], radio_range[1]); } + t->radio_freq(c, freq); return; } @@ -143,41 +139,28 @@ static void set_type(struct i2c_client *c, unsigned int type, enum tuner_admin_state new_admin_status) { struct tuner *t = i2c_get_clientdata(c); - unsigned int i; unsigned char buffer[4]; - /* sanity check */ if (type == UNSET || type == TUNER_ABSENT) { - printk("tuner 0x%02x: Tuner type absent\n",c->addr); + tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr); return; } if (type >= tuner_count) { - printk("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count); + tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count); return; } /* This code prevents against I2C early announces */ if (NULL == t->i2c.dev.driver) { - printk("tuner 0x%02x: I2C driver not registred yet!\n",c->addr); + tuner_dbg ("tuner 0x%02x: I2C driver not registred yet!\n", c->addr); - for (i=0;(i<5)&&(NULL == t->i2c.dev.driver);i++) { - msleep(1); /* Giver 1 ms for I2C */ - } - if (NULL == t->i2c.dev.driver) { - printk("tuner 0x%02x: I2C driver still not registred. Giving up!\n",c->addr); - t->type=type; - /* not registered yet */ - return; - } - tuner_info("tuner 0x%02x: Workaround worked\n",c->addr); + t->type=type; + return; } -/* if ((t->admin_status==T_UNINITIALIZED) && (t->type == type)) - return; -*/ - tuner_dbg("set tuner type to %d\n",type); t->type = type; + switch (t->type) { case TUNER_MT2032: microtune_init(c); @@ -187,7 +170,6 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_TEA5767: if (tea5767_tuner_init(c) == EINVAL) { - tuner_dbg("tuner is not a tea5767!\n"); t->type = TUNER_ABSENT; t->admin_status = T_UNINITIALIZED; return; @@ -210,6 +192,7 @@ static void set_type(struct i2c_client *c, unsigned int type, default_tuner_init(c); break; } + if (t->admin_status == T_UNINITIALIZED) t->admin_status = new_admin_status; @@ -218,43 +201,39 @@ static void set_type(struct i2c_client *c, unsigned int type, t->admin_status); } +/* + * This function apply tuner config to tuner specified + * by tun_addr structure. I addr is unset, then admin status + * and tun addr status is more precise then current status, + * it's applied. Otherwise status and type are applied only to + * tuner with exactly the same addr. +*/ + static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) { struct tuner *t = i2c_get_clientdata(c); - enum tuner_admin_state new_admin_status; - /* ADDR_UNSET defaults to first available tuner */ if (tun_addr->addr == ADDR_UNSET) { - /* If no Address specifyed, accepts only if tuner is */ - if (!(t->admin_status & tun_addr->v4l2_tuner)) - return; + if (t->admin_status & tun_addr->v4l2_tuner) + set_type(c, tun_addr->type, tun_addr->v4l2_tuner); + } else if (tun_addr->addr == c->addr) { set_type(c, tun_addr->type, tun_addr->v4l2_tuner); - } else { - new_admin_status = tun_addr->v4l2_tuner; - - /* Sets tuner to its configured value */ - if (tun_addr->addr == c->addr) - set_type(c, tun_addr->type, new_admin_status); } } static inline int check_mode(struct tuner *t, char *cmd) { if (1 << t->mode & t->admin_status) { - if (tuner_debug) { - switch (t->mode) { - case V4L2_TUNER_RADIO: - tuner_dbg("Cmd %s accepted for radio\n", cmd); - break; - case V4L2_TUNER_ANALOG_TV: - tuner_dbg("Cmd %s accepted for analog TV\n", - cmd); - break; - case V4L2_TUNER_DIGITAL_TV: - tuner_dbg("Cmd %s accepted for digital TV\n", - cmd); - break; - } + switch (t->mode) { + case V4L2_TUNER_RADIO: + tuner_dbg("Cmd %s accepted for radio\n", cmd); + break; + case V4L2_TUNER_ANALOG_TV: + tuner_dbg("Cmd %s accepted for analog TV\n", cmd); + break; + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("Cmd %s accepted for digital TV\n", cmd); + break; } return 0; } @@ -350,13 +329,13 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) /* TEA5767 autodetection code - only for addr = 0xc0 */ if (addr == 0x60) { - if (tea5767_autodetection(&t->i2c)!=EINVAL) { + if (tea5767_autodetection(&t->i2c) != EINVAL) { t->type = TUNER_TEA5767; - t->admin_status = T_RADIO|T_STANDBY; + t->admin_status = T_RADIO | T_STANDBY; default_admin_status &= ~T_RADIO; /* Should be just before return */ - i2c_attach_client(&t->i2c); + i2c_attach_client (&t->i2c); set_type(&t->i2c,t->type, t->admin_status); return 0; } @@ -364,14 +343,14 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) /* Initializes only the first adapter found */ if (default_admin_status != T_UNINITIALIZED) { - tuner_dbg("admin to card = 0x%02x\n", default_admin_status); + tuner_dbg ("Setting admin_status to 0x%02x\n", default_admin_status); t->admin_status = default_admin_status; default_admin_status = T_UNINITIALIZED; } /* Should be just before return */ - i2c_attach_client(&t->i2c); - set_type(&t->i2c,t->type, t->admin_status); + i2c_attach_client (&t->i2c); + set_type (&t->i2c,t->type, t->admin_status); return 0; } @@ -405,26 +384,27 @@ static int tuner_detach(struct i2c_client *client) return 0; } +/* + * Switch tuner to other mode. If tuner support both tv and radio, + * set another frequency to some value (This is needed for some pal + * tuners to avoid locking). Otherwise, just put second tuner in + * standby mode. + */ + static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { - int freq; - if (mode != t->mode) { + t->mode = mode; - /* If TV/Radio tuners are separate, put the other tuner in standby mode*/ if (check_mode(t, cmd) == EINVAL) { t->admin_status |= T_STANDBY; if (V4L2_TUNER_RADIO == mode) { - freq=400 * 16; /* Why 400 MHz? */ - set_tv_freq(client, freq); + set_tv_freq(client, 400 * 16); } else { - freq=87.5 * 16000; /* Is it the better value? */ - set_radio_freq(client, freq); + set_radio_freq(client, 87.5 * 16000); } - return EINVAL; } else { - /* Disables standby mode */ t->admin_status &= ~T_STANDBY; set_freq (client, t->freq); } @@ -432,15 +412,14 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, return 0; } -#define switch_v4l2() if (!t->using_v4l2 && tuner_debug) \ - tuner_info("switching to v4l2\n"); \ - t->using_v4l2 = 1; +#define switch_v4l2() if (!t->using_v4l2) \ + tuner_dbg("switching to v4l2\n"); \ + t->using_v4l2 = 1; static inline int check_v4l2(struct tuner *t) { if (t->using_v4l2) { - if (tuner_debug) - tuner_info("ignore v4l1 call\n"); + tuner_dbg ("ignore v4l1 call\n"); return EINVAL; } return 0; @@ -452,19 +431,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) unsigned int *iarg = (int *)arg; switch (cmd) { - /* --- configuration --- */ + /* --- configuration --- */ case TUNER_SET_TYPE: - if (tuner_debug) - tuner_dbg("Calling set_type for type=%d\n",*iarg); + tuner_dbg("Calling set_type for type=%d\n",*iarg); set_type(client, *iarg, T_RADIO | T_ANALOG_TV | T_DIGITAL_TV); break; case TUNER_SET_TYPE_ADDR: - if (tuner_debug) - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", - ((struct tuner_addr *)arg)->type, - ((struct tuner_addr *)arg)->addr, - ((struct tuner_addr *)arg)->v4l2_tuner); + tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", + ((struct tuner_addr *)arg)->type, + ((struct tuner_addr *)arg)->addr, + ((struct tuner_addr *)arg)->v4l2_tuner); set_addr(client, (struct tuner_addr *)arg); break; @@ -485,9 +462,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } break; - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ + case TDA9887_SET_CONFIG: + break; + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ case VIDIOCSCHAN: { static const v4l2_std_id map[] = { @@ -576,7 +555,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { v4l2_std_id *id = arg; - if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")==EINVAL) + if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD") + == EINVAL) return 0; switch_v4l2(); @@ -595,7 +575,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); if (V4L2_TUNER_RADIO == f->type && V4L2_TUNER_RADIO != t->mode) { - if (set_mode(client,t,f->type,"VIDIOC_S_FREQUENCY") == EINVAL) + if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") + == EINVAL) return 0; } set_freq(client,t->freq); @@ -620,21 +601,24 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL) return 0; switch_v4l2(); + if (V4L2_TUNER_RADIO == t->mode) { + if (t->has_signal) tuner->signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) { - tuner->rxsubchans = - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_MONO; - } else { - tuner->rxsubchans = - V4L2_TUNER_SUB_MONO; - } + + if (t->is_stereo(client)) { + tuner->rxsubchans = + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_MONO; + } else { + tuner->rxsubchans = + V4L2_TUNER_SUB_MONO; } + tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + tuner->audmode = t->audmode; tuner->rangelow = radio_range[0] * 16000; @@ -645,35 +629,23 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } break; } - case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */ + case VIDIOC_S_TUNER: { struct v4l2_tuner *tuner = arg; if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL) return 0; + switch_v4l2(); - /* To switch the audio mode, applications initialize the - index and audmode fields and the reserved array and - call the VIDIOC_S_TUNER ioctl. */ - /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, - V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2, - V4L2_TUNER_MODE_SAP */ if (V4L2_TUNER_RADIO == t->mode) { - if (tuner->audmode == V4L2_TUNER_MODE_MONO) - t->audmode = V4L2_TUNER_MODE_MONO; - else - t->audmode = V4L2_TUNER_MODE_STEREO; - + t->audmode = tuner->audmode; set_radio_freq(client, t->freq); } break; } - case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */ - break; default: tuner_dbg("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); - /* nothing */ break; } @@ -682,20 +654,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) static int tuner_suspend(struct device *dev, u32 state, u32 level) { - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); + struct i2c_client *c = container_of (dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("suspend\n"); + tuner_dbg ("suspend\n"); /* FIXME: power down ??? */ return 0; } static int tuner_resume(struct device *dev, u32 level) { - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); + struct i2c_client *c = container_of (dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("resume\n"); + tuner_dbg ("resume\n"); if (t->freq) set_freq(c, t->freq); return 0; diff --git a/linux/drivers/media/video/tuner-simple.c b/linux/drivers/media/video/tuner-simple.c index c15b00f30..7c30a3a61 100644 --- a/linux/drivers/media/video/tuner-simple.c +++ b/linux/drivers/media/video/tuner-simple.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-simple.c,v 1.35 2005/06/28 23:41:47 mkrufky Exp $ + * $Id: tuner-simple.c,v 1.36 2005/07/02 14:53:02 nsh Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -221,7 +221,7 @@ static struct tunertype tuners[] = { 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623}, - { TEA5767_TUNER_NAME, Philips, RADIO, + { "Philips TEA5767HN FM Radio", Philips, RADIO, /* see tea5767.c for details */}, { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h index 7c1921f98..db62bae07 100644 --- a/linux/include/media/tuner.h +++ b/linux/include/media/tuner.h @@ -1,5 +1,5 @@ -/* $Id: tuner.h,v 1.37 2005/07/01 08:22:24 nsh Exp $ +/* $Id: tuner.h,v 1.38 2005/07/02 14:53:02 nsh Exp $ * tuner.h - definition for different tuners @@ -111,8 +111,6 @@ #define TUNER_TEA5767 62 /* Only FM Radio Tuner */ #define TUNER_PHILIPS_FMD1216ME_MK3 63 -#define TEA5767_TUNER_NAME "Philips TEA5767HN FM Radio" - #define NOTUNER 0 #define PAL 1 /* PAL_BG */ #define PAL_I 2 @@ -135,14 +133,6 @@ #define TCL 11 #define THOMSON 12 -enum v4l_radio_tuner { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - - #define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ #define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ #define TUNER_SET_TYPE_ADDR _IOW('T',3,int) /* set tuner type and I2C addr */ |