msp34xx.c revision 172836
1155324Simp/*- 2155324Simp * Copyright (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> 3155324Simp * All rights reserved. 4155324Simp * 5155324Simp * Redistribution and use in source and binary forms, with or without 6155324Simp * modification, are permitted provided that the following conditions 7155324Simp * are met: 8155324Simp * 1. Redistributions of source code must retain the above copyright 9155324Simp * notice, this list of conditions and the following disclaimer. 10155324Simp * 2. Redistributions in binary form must reproduce the above copyright 11155324Simp * notice, this list of conditions and the following disclaimer in the 12155324Simp * documentation and/or other materials provided with the distribution. 13155324Simp * 14155324Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15155324Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16155324Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17155324Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18155324Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19155324Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20155324Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21155324Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22155324Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23155324Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24155324Simp * SUCH DAMAGE. 25155324Simp * 26155324Simp * $FreeBSD: head/sys/dev/bktr/msp34xx.c 172836 2007-10-20 23:23:23Z julian $ 27155324Simp */ 28155324Simp 29155324Simp/* 30155324Simp * programming the msp34* sound processor family 31155324Simp * 32163522Simp * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> 33155324Simp * 34155324Simp * what works and what doesn't: 35155324Simp * 36155324Simp * AM-Mono 37155324Simp * Support for Hauppauge cards added (decoding handled by tuner) added by 38155324Simp * Frederic Crozat <fcrozat@mail.dotcom.fr> 39155324Simp * 40155324Simp * FM-Mono 41155324Simp * should work. The stereo modes are backward compatible to FM-mono, 42155324Simp * therefore FM-Mono should be allways available. 43155324Simp * 44155324Simp * FM-Stereo (B/G, used in germany) 45155324Simp * should work, with autodetect 46155324Simp * 47155324Simp * FM-Stereo (satellite) 48163522Simp * should work, no autodetect (i.e. default is mono, but you can 49155324Simp * switch to stereo -- untested) 50155324Simp * 51155324Simp * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) 52155324Simp * should work, with autodetect. Support for NICAM was added by 53155324Simp * Pekka Pietikainen <pp@netppl.fi> 54155324Simp * 55155324Simp * 56155324Simp * TODO: 57155324Simp * - better SAT support 58155324Simp * 59155324Simp * 60155324Simp * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) 61155324Simp * using soundcore instead of OSS 62155324Simp * 63155324Simp * 64155324Simp * The FreeBSD modifications by Alexander Langer <alex@FreeBSD.org> 65155324Simp * are in the public domain. Please contact me (Alex) and not Gerd for 66155324Simp * any problems you encounter under FreeBSD. 67155324Simp * 68155324Simp * FreeBSD TODO: 69155324Simp * - mutex handling (currently not mp-safe) 70155324Simp * - the various options here as loader tunables or compile time or whatever 71155324Simp * - how does the new dolby flag work with the current dpl_* stuff? 72155324Simp * Maybe it's just enough to set the dolby flag to 1 and it works. 73155324Simp * As I don't have a dolby card myself, I can't test it, though. 74155324Simp */ 75165778Sticso 76156831Simp#include "opt_bktr.h" /* Include any kernel config options */ 77155324Simp#ifdef BKTR_NEW_MSP34XX_DRIVER /* file only needed for new driver */ 78155324Simp 79155324Simp#include <sys/param.h> 80155324Simp#include <sys/systm.h> 81155324Simp#include <sys/kernel.h> 82155324Simp#include <sys/vnode.h> 83155324Simp 84155324Simp#include <sys/unistd.h> 85155324Simp#include <sys/kthread.h> 86155324Simp#include <sys/malloc.h> 87155324Simp 88155324Simp#ifdef BKTR_USE_FREEBSD_SMBUS 89155324Simp#include <sys/bus.h> /* required by bktr_reg.h */ 90157562Simp#endif 91155324Simp 92155324Simp#include <machine/bus.h> /* required by bktr_reg.h */ 93157562Simp 94157562Simp#include <dev/bktr/ioctl_meteor.h> 95155324Simp#include <dev/bktr/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ 96155324Simp#include <dev/bktr/bktr_reg.h> 97155324Simp#include <dev/bktr/bktr_tuner.h> 98155324Simp#include <dev/bktr/bktr_audio.h> 99155324Simp#include <dev/bktr/bktr_core.h> 100159708Simp 101155324Simp#define VIDEO_MODE_PAL 0 102155324Simp#define VIDEO_MODE_NTSC 1 103155324Simp#define VIDEO_MODE_SECAM 2 104155324Simp#define VIDEO_MODE_AUTO 3 105155324Simp 106155324Simp#define VIDEO_SOUND_MONO 1 107155324Simp#define VIDEO_SOUND_STEREO 2 108155324Simp#define VIDEO_SOUND_LANG1 4 109155324Simp#define VIDEO_SOUND_LANG2 8 110155324Simp 111155324Simp#define DFP_COUNT 0x41 112155324Simpstatic const int bl_dfp[] = { 113155324Simp 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a, 114155324Simp 0x0b, 0x0d, 0x0e, 0x10 115155324Simp}; 116155324Simp 117155324Simpstruct msp3400c { 118155324Simp int simple; 119155324Simp int nicam; 120155324Simp int mode; 121155324Simp int norm; 122155324Simp int stereo; 123155324Simp int nicam_on; 124155324Simp int acb; 125155324Simp int main, second; /* sound carrier */ 126155324Simp int input; 127155324Simp 128155324Simp int muted; 129155324Simp int left, right; /* volume */ 130155324Simp int bass, treble; 131155324Simp 132155324Simp /* shadow register set */ 133155324Simp int dfp_regs[DFP_COUNT]; 134155324Simp 135155324Simp /* thread */ 136155324Simp struct proc *kthread; 137155324Simp char *threaddesc; 138155324Simp 139155324Simp int active,restart,rmmod; 140155324Simp 141155324Simp int watch_stereo; 142155324Simp int halt_thread; 143155324Simp}; 144155324Simp 145155324Simp#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ 146155324Simp 147155324Simp/* ---------------------------------------------------------------------- */ 148155324Simp 149155324Simp#define dprintk(...) do { \ 150155445Scognet if (bootverbose) { \ 151155324Simp printf("%s: ", bktr_name(client)); \ 152155324Simp printf(__VA_ARGS__); \ 153155324Simp } \ 154155324Simp} while (0) 155155324Simp 156155324Simp/* ---------------------------------------------------------------------- */ 157155324Simp 158155324Simp#define I2C_MSP3400C 0x80 159155324Simp#define I2C_MSP3400C_DEM 0x10 160155324Simp#define I2C_MSP3400C_DFP 0x12 161155324Simp 162155324Simp/* ----------------------------------------------------------------------- */ 163155324Simp/* functions for talking to the MSP3400C Sound processor */ 164155324Simp 165155324Simpstatic int msp3400c_reset(bktr_ptr_t client) 166155324Simp{ 167155324Simp /* use our own which handles config(8) options */ 168155324Simp msp_dpl_reset(client, client->msp_addr); 169155324Simp 170163522Simp return 0; 171163522Simp} 172155324Simp 173155324Simpstatic int 174155324Simpmsp3400c_read(bktr_ptr_t client, int dev, int addr) 175155324Simp{ 176155324Simp /* use our own */ 177155324Simp return(msp_dpl_read(client, client->msp_addr, dev, addr)); 178155324Simp} 179155324Simp 180159708Simpstatic int 181159708Simpmsp3400c_write(bktr_ptr_t client, int dev, int addr, int val) 182163522Simp{ 183163522Simp /* use our own */ 184163522Simp msp_dpl_write(client, client->msp_addr, dev, addr, val); 185163522Simp 186163522Simp return(0); 187163522Simp} 188163522Simp 189155324Simp/* ------------------------------------------------------------------------ */ 190155324Simp 191155324Simp/* This macro is allowed for *constants* only, gcc must calculate it 192155324Simp at compile time. Remember -- no floats in kernel mode */ 193155324Simp#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) 194155324Simp 195155445Scognet#define MSP_MODE_AM_DETECT 0 196155324Simp#define MSP_MODE_FM_RADIO 2 197155405Scognet#define MSP_MODE_FM_TERRA 3 198155324Simp#define MSP_MODE_FM_SAT 4 199155324Simp#define MSP_MODE_FM_NICAM1 5 200155324Simp#define MSP_MODE_FM_NICAM2 6 201155324Simp#define MSP_MODE_AM_NICAM 7 202155324Simp#define MSP_MODE_BTSC 8 203155324Simp#define MSP_MODE_EXTERN 9 204155324Simp 205155324Simpstatic struct MSP_INIT_DATA_DEM { 206155324Simp int fir1[6]; 207155324Simp int fir2[6]; 208165779Sticso int cdo1; 209165779Sticso int cdo2; 210155324Simp int ad_cv; 211155324Simp int mode_reg; 212155324Simp int dfp_src; 213155324Simp int dfp_matrix; 214155324Simp} msp_init_data[] = { 215155324Simp /* AM (for carrier detect / msp3400) */ 216155324Simp { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 }, 217155324Simp MSP_CARRIER(5.5), MSP_CARRIER(5.5), 218155324Simp 0x00d0, 0x0500, 0x0020, 0x3000}, 219155324Simp 220155324Simp /* AM (for carrier detect / msp3410) */ 221155324Simp { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 }, 222155324Simp MSP_CARRIER(5.5), MSP_CARRIER(5.5), 223155324Simp 0x00d0, 0x0100, 0x0020, 0x3000}, 224155324Simp 225155324Simp /* FM Radio */ 226155324Simp { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, 227155324Simp MSP_CARRIER(10.7), MSP_CARRIER(10.7), 228155324Simp 0x00d0, 0x0480, 0x0020, 0x3000 }, 229155324Simp 230155324Simp /* Terrestial FM-mono + FM-stereo */ 231155324Simp { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, 232155324Simp MSP_CARRIER(5.5), MSP_CARRIER(5.5), 233155324Simp 0x00d0, 0x0480, 0x0030, 0x3000}, 234155324Simp 235155324Simp /* Sat FM-mono */ 236155324Simp { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 }, 237155324Simp MSP_CARRIER(6.5), MSP_CARRIER(6.5), 238155324Simp 0x00c6, 0x0480, 0x0000, 0x3000}, 239155324Simp 240155324Simp /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ 241155324Simp { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, 242155324Simp MSP_CARRIER(5.5), MSP_CARRIER(5.5), 243155324Simp 0x00d0, 0x0040, 0x0120, 0x3000}, 244155324Simp 245155324Simp /* NICAM/FM -- I (6.0/6.552) */ 246155324Simp { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, 247155324Simp MSP_CARRIER(6.0), MSP_CARRIER(6.0), 248155324Simp 0x00d0, 0x0040, 0x0120, 0x3000}, 249155324Simp 250155324Simp /* NICAM/AM -- L (6.5/5.85) */ 251155324Simp { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, 252155324Simp MSP_CARRIER(6.5), MSP_CARRIER(6.5), 253155324Simp 0x00c6, 0x0140, 0x0120, 0x7c03}, 254155324Simp}; 255155324Simp 256155324Simpstruct CARRIER_DETECT { 257155324Simp int cdo; 258157562Simp char *name; 259157562Simp}; 260157562Simp 261157562Simpstatic struct CARRIER_DETECT carrier_detect_main[] = { 262157562Simp /* main carrier */ 263157562Simp { MSP_CARRIER(4.5), "4.5 NTSC" }, 264157562Simp { MSP_CARRIER(5.5), "5.5 PAL B/G" }, 265157562Simp { MSP_CARRIER(6.0), "6.0 PAL I" }, 266157562Simp { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } 267157562Simp}; 268157562Simp 269157562Simpstatic struct CARRIER_DETECT carrier_detect_55[] = { 270157562Simp /* PAL B/G */ 271157562Simp { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, 272157562Simp { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } 273163937Simp}; 274157562Simp 275157562Simpstatic struct CARRIER_DETECT carrier_detect_65[] = { 276157562Simp /* PAL SAT / SECAM */ 277157562Simp { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, 278163937Simp { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, 279157562Simp { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, 280157562Simp { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, 281157562Simp { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, 282157562Simp { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, 283157562Simp}; 284155324Simp 285155324Simp#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) 286155324Simp 287155324Simp/* ----------------------------------------------------------------------- */ 288155324Simp 289155324Simp#define SCART_MASK 0 290155324Simp#define SCART_IN1 1 291155324Simp#define SCART_IN2 2 292155324Simp#define SCART_IN1_DA 3 293155324Simp#define SCART_IN2_DA 4 294155324Simp#define SCART_IN3 5 295155324Simp#define SCART_IN4 6 296155324Simp#define SCART_MONO 7 297155324Simp#define SCART_MUTE 8 298155324Simp 299155324Simpstatic int scarts[3][9] = { 300155324Simp /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ 301155324Simp { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, 302155324Simp { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, 303155324Simp { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, 304155324Simp}; 305155324Simp 306155324Simpstatic char *scart_names[] = { 307155324Simp "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" 308155324Simp}; 309155324Simp 310155324Simpstatic void 311155324Simpmsp3400c_set_scart(bktr_ptr_t client, int in, int out) 312155324Simp{ 313155324Simp struct msp3400c *msp = client->msp3400c_info; 314155324Simp 315155324Simp if (-1 == scarts[out][in]) 316155324Simp return; 317155324Simp 318155324Simp dprintk("msp34xx: scart switch: %s => %d\n",scart_names[in],out); 319155324Simp msp->acb &= ~scarts[out][SCART_MASK]; 320155324Simp msp->acb |= scarts[out][in]; 321155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb); 322155324Simp} 323155324Simp 324155324Simp/* ------------------------------------------------------------------------ */ 325155324Simp 326155324Simpstatic void msp3400c_setcarrier(bktr_ptr_t client, int cdo1, int cdo2) 327155324Simp{ 328155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); 329155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); 330155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); 331155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); 332155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ 333155324Simp} 334155324Simp 335155324Simpstatic void msp3400c_setvolume(bktr_ptr_t client, 336155324Simp int muted, int left, int right) 337163522Simp{ 338155324Simp int vol = 0,val = 0,balance = 0; 339155324Simp 340155324Simp if (!muted) { 341155324Simp vol = (left > right) ? left : right; 342155324Simp val = (vol * 0x73 / 65535) << 8; 343155324Simp } 344155324Simp if (vol > 0) { 345155324Simp balance = ((right-left) * 127) / vol; 346155324Simp } 347155324Simp 348155324Simp dprintk("msp34xx: setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n", 349155324Simp muted ? "on" : "off", left, right, val>>8, balance); 350155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ 351155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ 352155324Simp /* scart - on/off only */ 353155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); 354155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8); 355155324Simp} 356155324Simp 357155324Simpstatic void msp3400c_setbass(bktr_ptr_t client, int bass) 358155324Simp{ 359155324Simp int val = ((bass-32768) * 0x60 / 65535) << 8; 360155324Simp 361155324Simp dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8); 362155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ 363155324Simp} 364155324Simp 365155324Simpstatic void msp3400c_settreble(bktr_ptr_t client, int treble) 366155324Simp{ 367155324Simp int val = ((treble-32768) * 0x60 / 65535) << 8; 368155324Simp 369155324Simp dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8); 370155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ 371155324Simp} 372155324Simp 373155324Simpstatic void msp3400c_setmode(bktr_ptr_t client, int type) 374155324Simp{ 375156831Simp struct msp3400c *msp = client->msp3400c_info; 376156831Simp int i; 377155324Simp 378157562Simp dprintk("msp3400: setmode: %d\n",type); 379155324Simp msp->mode = type; 380155324Simp msp->stereo = VIDEO_SOUND_MONO; 381155324Simp 382155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ 383155324Simp msp_init_data[type].ad_cv); 384157562Simp 385157562Simp for (i = 5; i >= 0; i--) /* fir 1 */ 386157562Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, 387155324Simp msp_init_data[type].fir1[i]); 388157562Simp 389157562Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ 390157562Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); 391155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); 392157562Simp for (i = 5; i >= 0; i--) 393156831Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 394155324Simp msp_init_data[type].fir2[i]); 395155324Simp 396155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ 397155324Simp msp_init_data[type].mode_reg); 398155324Simp 399155324Simp msp3400c_setcarrier(client, msp_init_data[type].cdo1, 400155324Simp msp_init_data[type].cdo2); 401155324Simp 402155324Simp msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ 403155324Simp 404155324Simp if (client->dolby) { 405155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, 406155324Simp 0x0520); /* I2S1 */ 407155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, 408155324Simp 0x0620); /* I2S2 */ 409155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, 410155324Simp msp_init_data[type].dfp_src); 411155324Simp } else { 412155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, 413155324Simp msp_init_data[type].dfp_src); 414155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, 415155324Simp msp_init_data[type].dfp_src); 416155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, 417155324Simp msp_init_data[type].dfp_src); 418155324Simp } 419155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, 420155324Simp msp_init_data[type].dfp_src); 421155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 422155324Simp msp_init_data[type].dfp_matrix); 423155324Simp 424155324Simp if (msp->nicam) { 425155324Simp /* nicam prescale */ 426155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ 427155324Simp } 428155324Simp} 429155324Simp 430155324Simp/* turn on/off nicam + stereo */ 431155324Simpstatic void msp3400c_setstereo(bktr_ptr_t client, int mode) 432155324Simp{ 433155324Simp static char *strmode[] = { "0", "mono", "stereo", "3", 434155324Simp "lang1", "5", "6", "7", "lang2" }; 435155324Simp struct msp3400c *msp = client->msp3400c_info; 436155324Simp int nicam=0; /* channel source: FM/AM or nicam */ 437155324Simp int src=0; 438155324Simp 439155324Simp /* switch demodulator */ 440155324Simp switch (msp->mode) { 441155324Simp case MSP_MODE_FM_TERRA: 442155324Simp dprintk("msp3400: FM setstereo: %s\n",strmode[mode]); 443155324Simp msp3400c_setcarrier(client,msp->second,msp->main); 444155324Simp switch (mode) { 445155324Simp case VIDEO_SOUND_STEREO: 446155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); 447155324Simp break; 448155324Simp case VIDEO_SOUND_MONO: 449155324Simp case VIDEO_SOUND_LANG1: 450155324Simp case VIDEO_SOUND_LANG2: 451155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); 452155324Simp break; 453155324Simp } 454155324Simp break; 455155324Simp case MSP_MODE_FM_SAT: 456155324Simp dprintk("msp3400: SAT setstereo: %s\n",strmode[mode]); 457155324Simp switch (mode) { 458155324Simp case VIDEO_SOUND_MONO: 459155324Simp msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); 460155324Simp break; 461155324Simp case VIDEO_SOUND_STEREO: 462155324Simp msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); 463155324Simp break; 464155324Simp case VIDEO_SOUND_LANG1: 465155324Simp msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); 466155324Simp break; 467155324Simp case VIDEO_SOUND_LANG2: 468155324Simp msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); 469155324Simp break; 470155324Simp } 471155324Simp break; 472155324Simp case MSP_MODE_FM_NICAM1: 473155324Simp case MSP_MODE_FM_NICAM2: 474155324Simp case MSP_MODE_AM_NICAM: 475155324Simp dprintk("msp3400: NICAM setstereo: %s\n",strmode[mode]); 476155324Simp msp3400c_setcarrier(client,msp->second,msp->main); 477155324Simp if (msp->nicam_on) 478155324Simp nicam=0x0100; 479155324Simp break; 480155324Simp case MSP_MODE_BTSC: 481155324Simp dprintk("msp3400: BTSC setstereo: %s\n",strmode[mode]); 482155324Simp nicam=0x0300; 483155324Simp break; 484155324Simp case MSP_MODE_EXTERN: 485155324Simp dprintk("msp3400: extern setstereo: %s\n",strmode[mode]); 486155324Simp nicam = 0x0200; 487155324Simp break; 488155324Simp case MSP_MODE_FM_RADIO: 489155324Simp dprintk("msp3400: FM-Radio setstereo: %s\n",strmode[mode]); 490155324Simp break; 491155324Simp default: 492155324Simp dprintk("msp3400: mono setstereo\n"); 493163937Simp return; 494163937Simp } 495163937Simp 496163937Simp /* switch audio */ 497163937Simp switch (mode) { 498163937Simp case VIDEO_SOUND_STEREO: 499163937Simp src = 0x0020 | nicam; 500163937Simp#if 0 501163937Simp /* spatial effect */ 502163937Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); 503163937Simp#endif 504163937Simp break; 505163937Simp case VIDEO_SOUND_MONO: 506163937Simp if (msp->mode == MSP_MODE_AM_NICAM) { 507163937Simp dprintk("msp3400: switching to AM mono\n"); 508163937Simp /* AM mono decoding is handled by tuner, not MSP chip */ 509163937Simp /* SCART switching control register */ 510155324Simp msp3400c_set_scart(client,SCART_MONO,0); 511155324Simp src = 0x0200; 512155324Simp break; 513163937Simp } 514155324Simp case VIDEO_SOUND_LANG1: 515155324Simp src = 0x0000 | nicam; 516163937Simp break; 517155324Simp case VIDEO_SOUND_LANG2: 518155324Simp src = 0x0010 | nicam; 519155324Simp break; 520155324Simp } 521155324Simp dprintk("msp3400: setstereo final source/matrix = 0x%x\n", src); 522155324Simp 523155324Simp if (client->dolby) { 524155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); 525155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); 526155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); 527155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); 528155324Simp } else { 529163937Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); 530163937Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); 531155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); 532155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); 533155324Simp } 534155324Simp} 535155324Simp 536155324Simpstatic void 537155324Simpmsp3400c_print_mode(struct msp3400c *msp) 538155324Simp{ 539155324Simp if (msp->main == msp->second) { 540155324Simp printf("bktr: msp3400: mono sound carrier: %d.%03d MHz\n", 541163937Simp msp->main/910000,(msp->main/910)%1000); 542163937Simp } else { 543155324Simp printf("bktr: msp3400: main sound carrier: %d.%03d MHz\n", 544155324Simp msp->main/910000,(msp->main/910)%1000); 545155324Simp } 546163937Simp if (msp->mode == MSP_MODE_FM_NICAM1 || 547163937Simp msp->mode == MSP_MODE_FM_NICAM2) 548163937Simp printf("bktr: msp3400: NICAM/FM carrier : %d.%03d MHz\n", 549163937Simp msp->second/910000,(msp->second/910)%1000); 550163937Simp if (msp->mode == MSP_MODE_AM_NICAM) 551163937Simp printf("bktr: msp3400: NICAM/AM carrier : %d.%03d MHz\n", 552155324Simp msp->second/910000,(msp->second/910)%1000); 553155324Simp if (msp->mode == MSP_MODE_FM_TERRA && 554163937Simp msp->main != msp->second) { 555163937Simp printf("bktr: msp3400: FM-stereo carrier : %d.%03d MHz\n", 556163937Simp msp->second/910000,(msp->second/910)%1000); 557163937Simp } 558163937Simp} 559163937Simp 560155324Simpstatic void 561155324Simpmsp3400c_restore_dfp(bktr_ptr_t client) 562155324Simp{ 563155324Simp struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 564155324Simp int i; 565155324Simp 566155324Simp for (i = 0; i < DFP_COUNT; i++) { 567163937Simp if (-1 == msp->dfp_regs[i]) 568155324Simp continue; 569155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, i, msp->dfp_regs[i]); 570155324Simp } 571155324Simp} 572155324Simp 573155324Simp/* ----------------------------------------------------------------------- */ 574155324Simp 575155324Simpstruct REGISTER_DUMP { 576155324Simp int addr; 577155324Simp char *name; 578155445Scognet}; 579155445Scognet 580155445Scognetstruct REGISTER_DUMP d1[] = { 581155445Scognet { 0x007e, "autodetect" }, 582155445Scognet { 0x0023, "C_AD_BITS " }, 583155445Scognet { 0x0038, "ADD_BITS " }, 584155445Scognet { 0x003e, "CIB_BITS " }, 585155445Scognet { 0x0057, "ERROR_RATE" }, 586155445Scognet}; 587155324Simp 588155324Simpstatic int 589155324Simpautodetect_stereo(bktr_ptr_t client) 590155324Simp{ 591155324Simp struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 592163937Simp int val; 593163937Simp int newstereo = msp->stereo; 594163937Simp int newnicam = msp->nicam_on; 595155324Simp int update = 0; 596155324Simp 597155324Simp switch (msp->mode) { 598155324Simp case MSP_MODE_FM_TERRA: 599155324Simp val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); 600155324Simp if (val > 32767) 601155324Simp val -= 65536; 602155324Simp dprintk("msp34xx: stereo detect register: %d\n",val); 603155324Simp 604155324Simp if (val > 4096) { 605155324Simp newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO; 606155324Simp } else if (val < -4096) { 607155324Simp newstereo = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; 608155324Simp } else { 609155324Simp newstereo = VIDEO_SOUND_MONO; 610163937Simp } 611155324Simp newnicam = 0; 612155324Simp break; 613157562Simp case MSP_MODE_FM_NICAM1: 614157562Simp case MSP_MODE_FM_NICAM2: 615157562Simp case MSP_MODE_AM_NICAM: 616156831Simp val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); 617155324Simp dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1); 618155324Simp 619155324Simp if (val & 1) { 620155324Simp /* nicam synced */ 621155324Simp switch ((val & 0x1e) >> 1) { 622155324Simp case 0: 623157562Simp case 8: 624157562Simp newstereo = VIDEO_SOUND_STEREO; 625157562Simp break; 626157562Simp case 1: 627156831Simp case 9: 628156831Simp newstereo = VIDEO_SOUND_MONO 629156831Simp | VIDEO_SOUND_LANG1; 630163937Simp break; 631163937Simp case 2: 632157562Simp case 10: 633156831Simp newstereo = VIDEO_SOUND_MONO 634163937Simp | VIDEO_SOUND_LANG1 635156831Simp | VIDEO_SOUND_LANG2; 636155324Simp break; 637156831Simp default: 638156831Simp newstereo = VIDEO_SOUND_MONO; 639156831Simp break; 640163937Simp } 641163937Simp newnicam=1; 642156831Simp } else { 643156831Simp newnicam = 0; 644156831Simp newstereo = VIDEO_SOUND_MONO; 645156831Simp } 646156831Simp break; 647157562Simp case MSP_MODE_BTSC: 648157562Simp val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); 649163937Simp dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", 650163937Simp val, 651163937Simp (val & 0x0002) ? "no" : "yes", 652157562Simp (val & 0x0004) ? "no" : "yes", 653157562Simp (val & 0x0040) ? "stereo" : "mono", 654163937Simp (val & 0x0080) ? ", nicam 2nd mono" : "", 655156831Simp (val & 0x0100) ? ", bilingual/SAP" : ""); 656156831Simp newstereo = VIDEO_SOUND_MONO; 657163937Simp if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO; 658163937Simp if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1; 659163937Simp break; 660163937Simp } 661163937Simp if (newstereo != msp->stereo) { 662155324Simp update = 1; 663155324Simp dprintk("msp34xx: watch: stereo %d => %d\n", 664155324Simp msp->stereo,newstereo); 665156831Simp msp->stereo = newstereo; 666163937Simp } 667156831Simp if (newnicam != msp->nicam_on) { 668163937Simp update = 1; 669163937Simp dprintk("msp34xx: watch: nicam %d => %d\n", 670155324Simp msp->nicam_on,newnicam); 671163937Simp msp->nicam_on = newnicam; 672156831Simp } 673156831Simp return update; 674155324Simp} 675155324Simp 676163937Simp/* 677163937Simp * A kernel thread for msp3400 control -- we don't want to block the 678155324Simp * in the ioctl while doing the sound carrier & stereo detect 679163937Simp */ 680155324Simp 681155324Simp/* stereo/multilang monitoring */ 682155324Simpstatic void watch_stereo(bktr_ptr_t client) 683155324Simp{ 684155324Simp struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 685155324Simp 686155324Simp if (autodetect_stereo(client)) { 687155324Simp if (msp->stereo & VIDEO_SOUND_STEREO) 688155324Simp msp3400c_setstereo(client,VIDEO_SOUND_STEREO); 689155324Simp else if (msp->stereo & VIDEO_SOUND_LANG1) 690155324Simp msp3400c_setstereo(client,VIDEO_SOUND_LANG1); 691156831Simp else 692156831Simp msp3400c_setstereo(client,VIDEO_SOUND_MONO); 693156831Simp } 694156831Simp if (client->stereo_once) 695156831Simp msp->watch_stereo = 0; 696156831Simp 697156831Simp} 698155324Simp 699155324Simpstatic void msp3400c_thread(void *data) 700156831Simp{ 701155324Simp bktr_ptr_t client = data; 702155324Simp struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 703155324Simp 704155324Simp struct CARRIER_DETECT *cd; 705155324Simp int count, max1,max2,val1,val2, val,this; 706155324Simp 707155324Simp dprintk("msp3400: thread started\n"); 708155324Simp 709155324Simp mtx_lock(&Giant); 710155324Simp for (;;) { 711155324Simp if (msp->rmmod) 712155324Simp goto done; 713155324Simp tsleep(msp->kthread, PRIBIO, "idle", 0); 714155324Simp if (msp->rmmod) 715163937Simp goto done; 716155324Simp if (msp->halt_thread) { 717155324Simp msp->watch_stereo = 0; 718155324Simp msp->halt_thread = 0; 719155324Simp continue; 720155324Simp } 721155324Simp 722155324Simp if (VIDEO_MODE_RADIO == msp->norm || 723155324Simp MSP_MODE_EXTERN == msp->mode) 724155324Simp continue; /* nothing to do */ 725155324Simp 726155324Simp msp->active = 1; 727155324Simp 728155324Simp if (msp->watch_stereo) { 729155324Simp watch_stereo(client); 730155324Simp msp->active = 0; 731155324Simp continue; 732155324Simp } 733155324Simp 734159708Simp /* some time for the tuner to sync */ 735159708Simp tsleep(msp->kthread, PRIBIO, "tuner sync", hz/2); 736159708Simp 737159708Simp restart: 738159708Simp if (VIDEO_MODE_RADIO == msp->norm || 739155324Simp MSP_MODE_EXTERN == msp->mode) 740155324Simp continue; /* nothing to do */ 741155324Simp msp->restart = 0; 742155324Simp msp3400c_setvolume(client, msp->muted, 0, 0); 743155324Simp msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); 744155324Simp val1 = val2 = 0; 745155324Simp max1 = max2 = -1; 746155324Simp msp->watch_stereo = 0; 747156831Simp 748155324Simp /* carrier detect pass #1 -- main carrier */ 749155324Simp cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); 750155324Simp 751155324Simp if (client->amsound && (msp->norm == VIDEO_MODE_SECAM)) { 752155324Simp /* autodetect doesn't work well with AM ... */ 753155324Simp max1 = 3; 754155324Simp count = 0; 755155324Simp dprintk("msp3400: AM sound override\n"); 756155324Simp } 757165779Sticso 758165779Sticso for (this = 0; this < count; this++) { 759165779Sticso msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); 760155324Simp 761155324Simp tsleep(msp->kthread, PRIBIO, "carrier detect", hz/100); 762155324Simp 763155324Simp if (msp->restart) 764155324Simp msp->restart = 0; 765155324Simp 766163937Simp val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); 767163937Simp if (val > 32767) 768163937Simp val -= 65536; 769163937Simp if (val1 < val) 770155324Simp val1 = val, max1 = this; 771155324Simp dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); 772155324Simp } 773155324Simp 774155324Simp /* carrier detect pass #2 -- second (stereo) carrier */ 775155324Simp switch (max1) { 776155324Simp case 1: /* 5.5 */ 777155324Simp cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55); 778155324Simp break; 779155324Simp case 3: /* 6.5 */ 780155324Simp cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65); 781155324Simp break; 782155324Simp case 0: /* 4.5 */ 783155324Simp case 2: /* 6.0 */ 784163937Simp default: 785155324Simp cd = NULL; count = 0; 786155324Simp break; 787155324Simp } 788155324Simp 789155324Simp if (client->amsound && (msp->norm == VIDEO_MODE_SECAM)) { 790156831Simp /* autodetect doesn't work well with AM ... */ 791156831Simp cd = NULL; count = 0; max2 = 0; 792156831Simp } 793156831Simp for (this = 0; this < count; this++) { 794156831Simp msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); 795156831Simp 796156831Simp tsleep(msp->kthread, PRIBIO, "carrier detection", hz/100); 797156831Simp if (msp->restart) 798156831Simp goto restart; 799156831Simp 800156831Simp val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); 801156831Simp if (val > 32767) 802156831Simp val -= 65536; 803156831Simp if (val2 < val) 804156831Simp val2 = val, max2 = this; 805156831Simp dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); 806163937Simp } 807163937Simp 808163937Simp /* programm the msp3400 according to the results */ 809163937Simp msp->main = carrier_detect_main[max1].cdo; 810163937Simp switch (max1) { 811163937Simp case 1: /* 5.5 */ 812163937Simp if (max2 == 0) { 813163937Simp /* B/G FM-stereo */ 814163937Simp msp->second = carrier_detect_55[max2].cdo; 815163937Simp msp3400c_setmode(client, MSP_MODE_FM_TERRA); 816163937Simp msp->nicam_on = 0; 817156831Simp /* XXX why mono? this probably can do stereo... - Alex*/ 818163937Simp msp3400c_setstereo(client, VIDEO_SOUND_MONO); 819156831Simp msp->watch_stereo = 1; 820156831Simp } else if (max2 == 1 && msp->nicam) { 821156831Simp /* B/G NICAM */ 822156831Simp msp->second = carrier_detect_55[max2].cdo; 823156831Simp msp3400c_setmode(client, MSP_MODE_FM_NICAM1); 824155324Simp msp->nicam_on = 1; 825156831Simp msp3400c_setcarrier(client, msp->second, msp->main); 826156831Simp msp->watch_stereo = 1; 827156831Simp } else { 828156831Simp goto no_second; 829156831Simp } 830155324Simp break; 831156831Simp case 2: /* 6.0 */ 832156831Simp /* PAL I NICAM */ 833156831Simp msp->second = MSP_CARRIER(6.552); 834156831Simp msp3400c_setmode(client, MSP_MODE_FM_NICAM2); 835155324Simp msp->nicam_on = 1; 836156831Simp msp3400c_setcarrier(client, msp->second, msp->main); 837156831Simp msp->watch_stereo = 1; 838156831Simp break; 839155324Simp case 3: /* 6.5 */ 840155324Simp if (max2 == 1 || max2 == 2) { 841155324Simp /* D/K FM-stereo */ 842155324Simp msp->second = carrier_detect_65[max2].cdo; 843155324Simp msp3400c_setmode(client, MSP_MODE_FM_TERRA); 844155324Simp msp->nicam_on = 0; 845155324Simp msp3400c_setstereo(client, VIDEO_SOUND_MONO); 846155324Simp msp->watch_stereo = 1; 847155324Simp } else if (max2 == 0 && 848155324Simp msp->norm == VIDEO_MODE_SECAM) { 849155324Simp /* L NICAM or AM-mono */ 850155324Simp msp->second = carrier_detect_65[max2].cdo; 851155324Simp msp3400c_setmode(client, MSP_MODE_AM_NICAM); 852155324Simp msp->nicam_on = 0; 853155324Simp msp3400c_setstereo(client, VIDEO_SOUND_MONO); 854155324Simp msp3400c_setcarrier(client, msp->second, msp->main); 855155324Simp /* volume prescale for SCART (AM mono input) */ 856155324Simp msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); 857155324Simp msp->watch_stereo = 1; 858155324Simp } else if (max2 == 0 && msp->nicam) { 859155324Simp /* D/K NICAM */ 860155324Simp msp->second = carrier_detect_65[max2].cdo; 861155324Simp msp3400c_setmode(client, MSP_MODE_FM_NICAM1); 862155324Simp msp->nicam_on = 1; 863155324Simp msp3400c_setcarrier(client, msp->second, msp->main); 864155324Simp msp->watch_stereo = 1; 865155324Simp } else { 866155324Simp goto no_second; 867155324Simp } 868155324Simp break; 869155324Simp case 0: /* 4.5 */ 870155324Simp default: 871155324Simp no_second: 872155324Simp msp->second = carrier_detect_main[max1].cdo; 873155324Simp msp3400c_setmode(client, MSP_MODE_FM_TERRA); 874155324Simp msp->nicam_on = 0; 875155324Simp msp3400c_setcarrier(client, msp->second, msp->main); 876155324Simp msp->stereo = VIDEO_SOUND_MONO; 877155324Simp msp3400c_setstereo(client, VIDEO_SOUND_MONO); 878155405Scognet break; 879155324Simp } 880155324Simp 881155324Simp if (msp->watch_stereo) 882155324Simp watch_stereo(client); 883155324Simp 884155324Simp /* unmute + restore dfp registers */ 885155324Simp msp3400c_setvolume(client, msp->muted, msp->left, msp->right); 886155324Simp msp3400c_restore_dfp(client); 887155324Simp 888155324Simp if (bootverbose) 889155324Simp msp3400c_print_mode(msp); 890155324Simp 891155324Simp msp->active = 0; 892155324Simp } 893155324Simp 894155324Simpdone: 895155324Simp dprintk("msp3400: thread: exit\n"); 896155324Simp msp->active = 0; 897155324Simp 898155324Simp msp->kthread = NULL; 899155324Simp wakeup(&msp->kthread); 900155324Simp mtx_unlock(&Giant); 901155324Simp 902155324Simp kproc_exit(0); 903155324Simp} 904155324Simp 905155324Simp/* ----------------------------------------------------------------------- */ 906155324Simp/* this one uses the automatic sound standard detection of newer */ 907155324Simp/* msp34xx chip versions */ 908155324Simp 909155324Simpstatic struct MODES { 910155324Simp int retval; 911155324Simp int main, second; 912155324Simp char *name; 913155324Simp} modelist[] = { 914155324Simp { 0x0000, 0, 0, "ERROR" }, 915155324Simp { 0x0001, 0, 0, "autodetect start" }, 916155324Simp { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, 917155324Simp { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, 918155324Simp { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, 919155324Simp { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, 920157562Simp { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, 921157562Simp { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, 922165779Sticso { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, 923155324Simp { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, 924155324Simp { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, 925155324Simp { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, 926155324Simp { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, 927155324Simp { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, 928155324Simp { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, 929155324Simp { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, 930155324Simp { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, 931155324Simp { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, 932155324Simp { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, 933155324Simp { -1, 0, 0, NULL }, /* EOF */ 934155324Simp}; 935155324Simp 936155324Simpstatic void msp3410d_thread(void *data) 937155324Simp{ 938155324Simp bktr_ptr_t client = data; 939155324Simp struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 940155324Simp int mode,val,i,std; 941157562Simp int timo = 0; 942155324Simp 943157562Simp dprintk("msp3410: thread started\n"); 944155324Simp 945155324Simp mtx_lock(&Giant); 946155324Simp for (;;) { 947157562Simp if (msp->rmmod) 948157562Simp goto done; 949157562Simp if (!msp->watch_stereo) 950157562Simp timo = 0; 951157562Simp else 952165779Sticso timo = 10*hz; 953165779Sticso tsleep(msp->kthread, PRIBIO, "idle", timo); 954165779Sticso if (msp->rmmod) 955165779Sticso goto done; 956165779Sticso if (msp->halt_thread) { 957165779Sticso msp->watch_stereo = 0; 958165779Sticso msp->halt_thread = 0; 959165779Sticso dprintk("msp3410: thread halted\n"); 960165779Sticso continue; 961165779Sticso } 962165779Sticso 963165779Sticso if (msp->mode == MSP_MODE_EXTERN) 964165779Sticso continue; 965155324Simp 966155324Simp msp->active = 1; 967155324Simp 968155324Simp if (msp->watch_stereo) { 969155324Simp watch_stereo(client); 970155324Simp msp->active = 0; 971155324Simp continue; 972155324Simp } 973155324Simp 974155324Simp /* some time for the tuner to sync */ 975155324Simp tsleep(msp->kthread, PRIBIO, "tuner sync", hz/2); 976155324Simp 977155324Simp restart: 978155324Simp if (msp->mode == MSP_MODE_EXTERN) 979155324Simp continue; 980155324Simp msp->restart = 0; 981155324Simp msp->watch_stereo = 0; 982155324Simp 983155324Simp /* put into sane state (and mute) */ 984155324Simp msp3400c_reset(client); 985155324Simp 986155324Simp /* start autodetect */ 987155324Simp switch (msp->norm) { 988155324Simp case VIDEO_MODE_PAL: 989155324Simp mode = 0x1003; 990155324Simp std = 1; 991155324Simp break; 992155324Simp case VIDEO_MODE_NTSC: /* BTSC */ 993155324Simp mode = 0x2003; 994155324Simp std = 0x0020; 995155324Simp break; 996155324Simp case VIDEO_MODE_SECAM: 997155324Simp mode = 0x0003; 998155324Simp std = 1; 999155324Simp break; 1000155324Simp case VIDEO_MODE_RADIO: 1001155324Simp mode = 0x0003; 1002155324Simp std = 0x0040; 1003155324Simp break; 1004155324Simp default: 1005155324Simp mode = 0x0003; 1006155324Simp std = 1; 1007155324Simp break; 1008155324Simp } 1009155324Simp msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); 1010155324Simp msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); 1011155324Simp 1012155324Simp if (bootverbose) { 1013155324Simp int i; 1014155324Simp for (i = 0; modelist[i].name != NULL; i++) 1015155324Simp if (modelist[i].retval == std) 1016155324Simp break; 1017155324Simp dprintk("msp3410: setting mode: %s (0x%04x)\n", 1018155324Simp modelist[i].name ? modelist[i].name : "unknown",std); 1019155324Simp } 1020155324Simp 1021155324Simp if (std != 1) { 1022155324Simp /* programmed some specific mode */ 1023155324Simp val = std; 1024155324Simp } else { 1025155324Simp /* triggered autodetect */ 1026155324Simp for (;;) { 1027155324Simp tsleep(msp->kthread, PRIBIO, "autodetection", hz/10); 1028155324Simp if (msp->restart) 1029155324Simp goto restart; 1030155324Simp 1031155324Simp /* check results */ 1032155324Simp val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); 1033155324Simp if (val < 0x07ff) 1034155324Simp break; 1035155324Simp dprintk("msp3410: detection still in progress\n"); 1036155324Simp } 1037155324Simp } 1038155324Simp for (i = 0; modelist[i].name != NULL; i++) 1039155324Simp if (modelist[i].retval == val) 1040155324Simp break; 1041155324Simp dprintk("msp3410: current mode: %s (0x%04x)\n", 1042155324Simp modelist[i].name ? modelist[i].name : "unknown", 1043155324Simp val); 1044155324Simp msp->main = modelist[i].main; 1045155324Simp msp->second = modelist[i].second; 1046155324Simp 1047155324Simp if (client->amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { 1048155324Simp /* autodetection has failed, let backup */ 1049155324Simp dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n", 1050155324Simp modelist[8].name ? modelist[8].name : "unknown",val); 1051 val = 0x0009; 1052 msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); 1053 } 1054 1055 /* set various prescales */ 1056 msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */ 1057 msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ 1058 msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */ 1059 1060 /* set stereo */ 1061 switch (val) { 1062 case 0x0008: /* B/G NICAM */ 1063 case 0x000a: /* I NICAM */ 1064 if (val == 0x0008) 1065 msp->mode = MSP_MODE_FM_NICAM1; 1066 else 1067 msp->mode = MSP_MODE_FM_NICAM2; 1068 /* just turn on stereo */ 1069 msp->stereo = VIDEO_SOUND_STEREO; 1070 msp->nicam_on = 1; 1071 msp->watch_stereo = 1; 1072 msp3400c_setstereo(client,VIDEO_SOUND_STEREO); 1073 break; 1074 case 0x0009: 1075 msp->mode = MSP_MODE_AM_NICAM; 1076 msp->stereo = VIDEO_SOUND_MONO; 1077 msp->nicam_on = 1; 1078 msp3400c_setstereo(client,VIDEO_SOUND_MONO); 1079 msp->watch_stereo = 1; 1080 break; 1081 case 0x0020: /* BTSC */ 1082 /* just turn on stereo */ 1083 msp->mode = MSP_MODE_BTSC; 1084 msp->stereo = VIDEO_SOUND_STEREO; 1085 msp->nicam_on = 0; 1086 msp->watch_stereo = 1; 1087 msp3400c_setstereo(client,VIDEO_SOUND_STEREO); 1088 break; 1089 case 0x0040: /* FM radio */ 1090 msp->mode = MSP_MODE_FM_RADIO; 1091 msp->stereo = VIDEO_SOUND_STEREO; 1092 msp->nicam_on = 0; 1093 msp->watch_stereo = 0; 1094 /* scart routing */ 1095 msp3400c_set_scart(client,SCART_IN2,0); 1096 msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220); 1097 msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220); 1098 msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220); 1099 break; 1100 case 0x0003: 1101 msp->mode = MSP_MODE_FM_TERRA; 1102 msp->stereo = VIDEO_SOUND_STEREO; 1103 msp->nicam_on = 0; 1104 msp->watch_stereo = 1; 1105 msp3400c_setstereo(client,VIDEO_SOUND_STEREO); 1106 break; 1107 } 1108 1109 if (msp->watch_stereo) 1110 watch_stereo(client); 1111 1112 /* unmute + restore dfp registers */ 1113 msp3400c_setbass(client, msp->bass); 1114 msp3400c_settreble(client, msp->treble); 1115 msp3400c_setvolume(client, msp->muted, msp->left, msp->right); 1116 msp3400c_restore_dfp(client); 1117 1118 msp->active = 0; 1119 } 1120 1121done: 1122 dprintk("msp3410: thread: exit\n"); 1123 msp->active = 0; 1124 1125 msp->kthread = NULL; 1126 wakeup(&msp->kthread); 1127 mtx_unlock(&Giant); 1128 1129 kproc_exit(0); 1130} 1131 1132int msp_attach(bktr_ptr_t bktr) 1133{ 1134 struct msp3400c *msp; 1135 int rev1,rev2,i; 1136 int err; 1137 char buf[20]; 1138 1139 msp = (struct msp3400c *) malloc(sizeof(struct msp3400c), M_DEVBUF, M_NOWAIT); 1140 if (msp == NULL) 1141 return ENOMEM; 1142 bktr->msp3400c_info = msp; 1143 1144 memset(msp,0,sizeof(struct msp3400c)); 1145 msp->left = 65535; 1146 msp->right = 65535; 1147 msp->bass = 32768; 1148 msp->treble = 32768; 1149 msp->input = -1; 1150 msp->threaddesc = malloc(15 * sizeof(char), M_DEVBUF, M_NOWAIT); 1151 if (msp->threaddesc == NULL) { 1152 free(msp, M_DEVBUF); 1153 return ENOMEM; 1154 } 1155 snprintf(msp->threaddesc, 14, "%s_msp34xx_thread", bktr->bktr_xname); 1156 1157 for (i = 0; i < DFP_COUNT; i++) 1158 msp->dfp_regs[i] = -1; 1159 1160 msp3400c_reset(bktr); 1161 1162 rev1 = msp3400c_read(bktr, I2C_MSP3400C_DFP, 0x1e); 1163 if (-1 != rev1) 1164 rev2 = msp3400c_read(bktr, I2C_MSP3400C_DFP, 0x1f); 1165 if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) { 1166 free(msp->threaddesc, M_DEVBUF); 1167 free(msp, M_DEVBUF); 1168 bktr->msp3400c_info = NULL; 1169 printf("%s: msp3400: error while reading chip version\n", bktr_name(bktr)); 1170 return ENXIO; 1171 } 1172 1173#if 0 1174 /* this will turn on a 1kHz beep - might be useful for debugging... */ 1175 msp3400c_write(bktr,I2C_MSP3400C_DFP, 0x0014, 0x1040); 1176#endif 1177 1178 sprintf(buf,"MSP34%02d%c-%c%d", 1179 (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); 1180 msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; 1181 1182 if (bktr->mspsimple == -1) { 1183 /* default mode */ 1184 /* msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; */ 1185 msp->simple = ((rev1&0xff)+'@' > 'C'); 1186 } else { 1187 /* use kenv value */ 1188 msp->simple = bktr->mspsimple; 1189 } 1190 1191 /* hello world :-) */ 1192 if (bootverbose) { 1193 printf("%s: msp34xx: init: chip=%s", bktr_name(bktr), buf); 1194 if (msp->nicam) 1195 printf(", has NICAM support"); 1196 printf("\n"); 1197 } 1198 1199 /* startup control thread */ 1200 err = kproc_create(msp->simple ? msp3410d_thread : msp3400c_thread, 1201 bktr, &msp->kthread, (RFFDG | RFPROC), 0, 1202 msp->threaddesc); 1203 if (err) { 1204 printf("%s: Error returned by kproc_create: %d", bktr_name(bktr), err); 1205 free(msp->threaddesc, M_DEVBUF); 1206 free(msp, M_DEVBUF); 1207 bktr->msp3400c_info = NULL; 1208 return ENXIO; 1209 } 1210 wakeup(msp->kthread); 1211 1212 /* done */ 1213 return 0; 1214} 1215 1216int msp_detach(bktr_ptr_t client) 1217{ 1218 struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 1219 1220 /* shutdown control thread */ 1221 if (msp->kthread) 1222 { 1223 /* XXX mutex lock required */ 1224 mtx_lock(&Giant); 1225 msp->rmmod = 1; 1226 msp->watch_stereo = 0; 1227 wakeup(msp->kthread); 1228 1229 while (msp->kthread) 1230 tsleep(&msp->kthread, PRIBIO, "wait for kthread", hz/10); 1231 mtx_unlock(&Giant); 1232 } 1233 1234 if (client->msp3400c_info != NULL) { 1235 free(client->msp3400c_info, M_DEVBUF); 1236 client->msp3400c_info = NULL; 1237 } 1238 1239 msp3400c_reset(client); 1240 1241 return 0; 1242} 1243 1244void msp_wake_thread(bktr_ptr_t client) 1245{ 1246 struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 1247 1248 msp3400c_setvolume(client,msp->muted,0,0); 1249 msp->watch_stereo=0; 1250 if (msp->active) 1251 msp->restart = 1; 1252 wakeup(msp->kthread); 1253} 1254 1255void msp_halt_thread(bktr_ptr_t client) 1256{ 1257 struct msp3400c *msp = (struct msp3400c*)client->msp3400c_info; 1258 1259 msp3400c_setvolume(client,msp->muted,0,0); 1260 if (msp->active) 1261 msp->restart = 1; 1262 msp->halt_thread = 1; 1263 wakeup(msp->kthread); 1264} 1265#endif /* BKTR_NEW_MSP34XX_DRIVER */ 1266