linux/drivers/media/pci/cx88/cx88-tvaudio.c
<<
>>
Prefs
   1/*
   2
   3    cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
   4
   5     (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version]
   6     (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
   7     (c) 2003 Gerd Knorr <kraxel@bytesex.org>
   8
   9    -----------------------------------------------------------------------
  10
  11    Lot of voodoo here.  Even the data sheet doesn't help to
  12    understand what is going on here, the documentation for the audio
  13    part of the cx2388x chip is *very* bad.
  14
  15    Some of this comes from party done linux driver sources I got from
  16    [undocumented].
  17
  18    Some comes from the dscaler sources, one of the dscaler driver guy works
  19    for Conexant ...
  20
  21    -----------------------------------------------------------------------
  22
  23    This program is free software; you can redistribute it and/or modify
  24    it under the terms of the GNU General Public License as published by
  25    the Free Software Foundation; either version 2 of the License, or
  26    (at your option) any later version.
  27
  28    This program is distributed in the hope that it will be useful,
  29    but WITHOUT ANY WARRANTY; without even the implied warranty of
  30    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31    GNU General Public License for more details.
  32
  33    You should have received a copy of the GNU General Public License
  34    along with this program; if not, write to the Free Software
  35    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  36*/
  37
  38#include <linux/module.h>
  39#include <linux/errno.h>
  40#include <linux/freezer.h>
  41#include <linux/kernel.h>
  42#include <linux/mm.h>
  43#include <linux/poll.h>
  44#include <linux/signal.h>
  45#include <linux/ioport.h>
  46#include <linux/types.h>
  47#include <linux/interrupt.h>
  48#include <linux/vmalloc.h>
  49#include <linux/init.h>
  50#include <linux/delay.h>
  51#include <linux/kthread.h>
  52
  53#include "cx88.h"
  54
  55static unsigned int audio_debug;
  56module_param(audio_debug, int, 0644);
  57MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
  58
  59static unsigned int always_analog;
  60module_param(always_analog,int,0644);
  61MODULE_PARM_DESC(always_analog,"force analog audio out");
  62
  63static unsigned int radio_deemphasis;
  64module_param(radio_deemphasis,int,0644);
  65MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
  66                 "0=None, 1=50us (elsewhere), 2=75us (USA)");
  67
  68#define dprintk(fmt, arg...)    if (audio_debug) \
  69        printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
  70
  71/* ----------------------------------------------------------- */
  72
  73static const char * const aud_ctl_names[64] = {
  74        [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
  75        [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
  76        [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
  77        [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
  78        [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
  79        [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
  80        [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
  81        [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
  82        [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
  83        [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
  84        [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
  85        [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
  86        [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
  87        [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
  88        [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
  89        [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
  90        [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
  91        [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
  92        [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
  93        [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
  94        [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
  95        [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
  96        [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
  97};
  98
  99struct rlist {
 100        u32 reg;
 101        u32 val;
 102};
 103
 104static void set_audio_registers(struct cx88_core *core, const struct rlist *l)
 105{
 106        int i;
 107
 108        for (i = 0; l[i].reg; i++) {
 109                switch (l[i].reg) {
 110                case AUD_PDF_DDS_CNST_BYTE2:
 111                case AUD_PDF_DDS_CNST_BYTE1:
 112                case AUD_PDF_DDS_CNST_BYTE0:
 113                case AUD_QAM_MODE:
 114                case AUD_PHACC_FREQ_8MSB:
 115                case AUD_PHACC_FREQ_8LSB:
 116                        cx_writeb(l[i].reg, l[i].val);
 117                        break;
 118                default:
 119                        cx_write(l[i].reg, l[i].val);
 120                        break;
 121                }
 122        }
 123}
 124
 125static void set_audio_start(struct cx88_core *core, u32 mode)
 126{
 127        /* mute */
 128        cx_write(AUD_VOL_CTL, (1 << 6));
 129
 130        /* start programming */
 131        cx_write(AUD_INIT, mode);
 132        cx_write(AUD_INIT_LD, 0x0001);
 133        cx_write(AUD_SOFT_RESET, 0x0001);
 134}
 135
 136static void set_audio_finish(struct cx88_core *core, u32 ctl)
 137{
 138        u32 volume;
 139
 140        /* restart dma; This avoids buzz in NICAM and is good in others  */
 141        cx88_stop_audio_dma(core);
 142        cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
 143        cx88_start_audio_dma(core);
 144
 145        if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
 146                cx_write(AUD_I2SINPUTCNTL, 4);
 147                cx_write(AUD_BAUDRATE, 1);
 148                /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
 149                cx_set(AUD_CTL, EN_I2SOUT_ENABLE);
 150                cx_write(AUD_I2SOUTPUTCNTL, 1);
 151                cx_write(AUD_I2SCNTL, 0);
 152                /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
 153        }
 154        if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) {
 155                ctl |= EN_DAC_ENABLE;
 156                cx_write(AUD_CTL, ctl);
 157        }
 158
 159        /* finish programming */
 160        cx_write(AUD_SOFT_RESET, 0x0000);
 161
 162        /* unmute */
 163        volume = cx_sread(SHADOW_AUD_VOL_CTL);
 164        cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
 165
 166        core->last_change = jiffies;
 167}
 168
 169/* ----------------------------------------------------------- */
 170
 171static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
 172                                    u32 mode)
 173{
 174        static const struct rlist btsc[] = {
 175                {AUD_AFE_12DB_EN, 0x00000001},
 176                {AUD_OUT1_SEL, 0x00000013},
 177                {AUD_OUT1_SHIFT, 0x00000000},
 178                {AUD_POLY0_DDS_CONSTANT, 0x0012010c},
 179                {AUD_DMD_RA_DDS, 0x00c3e7aa},
 180                {AUD_DBX_IN_GAIN, 0x00004734},
 181                {AUD_DBX_WBE_GAIN, 0x00004640},
 182                {AUD_DBX_SE_GAIN, 0x00008d31},
 183                {AUD_DCOC_0_SRC, 0x0000001a},
 184                {AUD_IIR1_4_SEL, 0x00000021},
 185                {AUD_DCOC_PASS_IN, 0x00000003},
 186                {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
 187                {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
 188                {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
 189                {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
 190                {AUD_DN0_FREQ, 0x0000283b},
 191                {AUD_DN2_SRC_SEL, 0x00000008},
 192                {AUD_DN2_FREQ, 0x00003000},
 193                {AUD_DN2_AFC, 0x00000002},
 194                {AUD_DN2_SHFT, 0x00000000},
 195                {AUD_IIR2_2_SEL, 0x00000020},
 196                {AUD_IIR2_2_SHIFT, 0x00000000},
 197                {AUD_IIR2_3_SEL, 0x0000001f},
 198                {AUD_IIR2_3_SHIFT, 0x00000000},
 199                {AUD_CRDC1_SRC_SEL, 0x000003ce},
 200                {AUD_CRDC1_SHIFT, 0x00000000},
 201                {AUD_CORDIC_SHIFT_1, 0x00000007},
 202                {AUD_DCOC_1_SRC, 0x0000001b},
 203                {AUD_DCOC1_SHIFT, 0x00000000},
 204                {AUD_RDSI_SEL, 0x00000008},
 205                {AUD_RDSQ_SEL, 0x00000008},
 206                {AUD_RDSI_SHIFT, 0x00000000},
 207                {AUD_RDSQ_SHIFT, 0x00000000},
 208                {AUD_POLYPH80SCALEFAC, 0x00000003},
 209                { /* end of list */ },
 210        };
 211        static const struct rlist btsc_sap[] = {
 212                {AUD_AFE_12DB_EN, 0x00000001},
 213                {AUD_DBX_IN_GAIN, 0x00007200},
 214                {AUD_DBX_WBE_GAIN, 0x00006200},
 215                {AUD_DBX_SE_GAIN, 0x00006200},
 216                {AUD_IIR1_1_SEL, 0x00000000},
 217                {AUD_IIR1_3_SEL, 0x00000001},
 218                {AUD_DN1_SRC_SEL, 0x00000007},
 219                {AUD_IIR1_4_SHIFT, 0x00000006},
 220                {AUD_IIR2_1_SHIFT, 0x00000000},
 221                {AUD_IIR2_2_SHIFT, 0x00000000},
 222                {AUD_IIR3_0_SHIFT, 0x00000000},
 223                {AUD_IIR3_1_SHIFT, 0x00000000},
 224                {AUD_IIR3_0_SEL, 0x0000000d},
 225                {AUD_IIR3_1_SEL, 0x0000000e},
 226                {AUD_DEEMPH1_SRC_SEL, 0x00000014},
 227                {AUD_DEEMPH1_SHIFT, 0x00000000},
 228                {AUD_DEEMPH1_G0, 0x00004000},
 229                {AUD_DEEMPH1_A0, 0x00000000},
 230                {AUD_DEEMPH1_B0, 0x00000000},
 231                {AUD_DEEMPH1_A1, 0x00000000},
 232                {AUD_DEEMPH1_B1, 0x00000000},
 233                {AUD_OUT0_SEL, 0x0000003f},
 234                {AUD_OUT1_SEL, 0x0000003f},
 235                {AUD_DN1_AFC, 0x00000002},
 236                {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
 237                {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
 238                {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
 239                {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
 240                {AUD_IIR1_0_SEL, 0x0000001d},
 241                {AUD_IIR1_2_SEL, 0x0000001e},
 242                {AUD_IIR2_1_SEL, 0x00000002},
 243                {AUD_IIR2_2_SEL, 0x00000004},
 244                {AUD_IIR3_2_SEL, 0x0000000f},
 245                {AUD_DCOC2_SHIFT, 0x00000001},
 246                {AUD_IIR3_2_SHIFT, 0x00000001},
 247                {AUD_DEEMPH0_SRC_SEL, 0x00000014},
 248                {AUD_CORDIC_SHIFT_1, 0x00000006},
 249                {AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
 250                {AUD_DMD_RA_DDS, 0x00f696e6},
 251                {AUD_IIR2_3_SEL, 0x00000025},
 252                {AUD_IIR1_4_SEL, 0x00000021},
 253                {AUD_DN1_FREQ, 0x0000c965},
 254                {AUD_DCOC_PASS_IN, 0x00000003},
 255                {AUD_DCOC_0_SRC, 0x0000001a},
 256                {AUD_DCOC_1_SRC, 0x0000001b},
 257                {AUD_DCOC1_SHIFT, 0x00000000},
 258                {AUD_RDSI_SEL, 0x00000009},
 259                {AUD_RDSQ_SEL, 0x00000009},
 260                {AUD_RDSI_SHIFT, 0x00000000},
 261                {AUD_RDSQ_SHIFT, 0x00000000},
 262                {AUD_POLYPH80SCALEFAC, 0x00000003},
 263                { /* end of list */ },
 264        };
 265
 266        mode |= EN_FMRADIO_EN_RDS;
 267
 268        if (sap) {
 269                dprintk("%s SAP (status: unknown)\n", __func__);
 270                set_audio_start(core, SEL_SAP);
 271                set_audio_registers(core, btsc_sap);
 272                set_audio_finish(core, mode);
 273        } else {
 274                dprintk("%s (status: known-good)\n", __func__);
 275                set_audio_start(core, SEL_BTSC);
 276                set_audio_registers(core, btsc);
 277                set_audio_finish(core, mode);
 278        }
 279}
 280
 281static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
 282{
 283        static const struct rlist nicam_l[] = {
 284                {AUD_AFE_12DB_EN, 0x00000001},
 285                {AUD_RATE_ADJ1, 0x00000060},
 286                {AUD_RATE_ADJ2, 0x000000F9},
 287                {AUD_RATE_ADJ3, 0x000001CC},
 288                {AUD_RATE_ADJ4, 0x000002B3},
 289                {AUD_RATE_ADJ5, 0x00000726},
 290                {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
 291                {AUD_DEEMPHDENOM2_R, 0x00000000},
 292                {AUD_ERRLOGPERIOD_R, 0x00000064},
 293                {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
 294                {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
 295                {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
 296                {AUD_POLYPH80SCALEFAC, 0x00000003},
 297                {AUD_DMD_RA_DDS, 0x00C00000},
 298                {AUD_PLL_INT, 0x0000001E},
 299                {AUD_PLL_DDS, 0x00000000},
 300                {AUD_PLL_FRAC, 0x0000E542},
 301                {AUD_START_TIMER, 0x00000000},
 302                {AUD_DEEMPHNUMER1_R, 0x000353DE},
 303                {AUD_DEEMPHNUMER2_R, 0x000001B1},
 304                {AUD_PDF_DDS_CNST_BYTE2, 0x06},
 305                {AUD_PDF_DDS_CNST_BYTE1, 0x82},
 306                {AUD_PDF_DDS_CNST_BYTE0, 0x12},
 307                {AUD_QAM_MODE, 0x05},
 308                {AUD_PHACC_FREQ_8MSB, 0x34},
 309                {AUD_PHACC_FREQ_8LSB, 0x4C},
 310                {AUD_DEEMPHGAIN_R, 0x00006680},
 311                {AUD_RATE_THRES_DMD, 0x000000C0},
 312                { /* end of list */ },
 313        };
 314
 315        static const struct rlist nicam_bgdki_common[] = {
 316                {AUD_AFE_12DB_EN, 0x00000001},
 317                {AUD_RATE_ADJ1, 0x00000010},
 318                {AUD_RATE_ADJ2, 0x00000040},
 319                {AUD_RATE_ADJ3, 0x00000100},
 320                {AUD_RATE_ADJ4, 0x00000400},
 321                {AUD_RATE_ADJ5, 0x00001000},
 322                {AUD_ERRLOGPERIOD_R, 0x00000fff},
 323                {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
 324                {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
 325                {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
 326                {AUD_POLYPH80SCALEFAC, 0x00000003},
 327                {AUD_DEEMPHGAIN_R, 0x000023c2},
 328                {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
 329                {AUD_DEEMPHNUMER2_R, 0x0003023e},
 330                {AUD_DEEMPHDENOM1_R, 0x0000f3d0},
 331                {AUD_DEEMPHDENOM2_R, 0x00000000},
 332                {AUD_PDF_DDS_CNST_BYTE2, 0x06},
 333                {AUD_PDF_DDS_CNST_BYTE1, 0x82},
 334                {AUD_QAM_MODE, 0x05},
 335                { /* end of list */ },
 336        };
 337
 338        static const struct rlist nicam_i[] = {
 339                {AUD_PDF_DDS_CNST_BYTE0, 0x12},
 340                {AUD_PHACC_FREQ_8MSB, 0x3a},
 341                {AUD_PHACC_FREQ_8LSB, 0x93},
 342                { /* end of list */ },
 343        };
 344
 345        static const struct rlist nicam_default[] = {
 346                {AUD_PDF_DDS_CNST_BYTE0, 0x16},
 347                {AUD_PHACC_FREQ_8MSB, 0x34},
 348                {AUD_PHACC_FREQ_8LSB, 0x4c},
 349                { /* end of list */ },
 350        };
 351
 352        set_audio_start(core,SEL_NICAM);
 353        switch (core->tvaudio) {
 354        case WW_L:
 355                dprintk("%s SECAM-L NICAM (status: devel)\n", __func__);
 356                set_audio_registers(core, nicam_l);
 357                break;
 358        case WW_I:
 359                dprintk("%s PAL-I NICAM (status: known-good)\n", __func__);
 360                set_audio_registers(core, nicam_bgdki_common);
 361                set_audio_registers(core, nicam_i);
 362                break;
 363        case WW_NONE:
 364        case WW_BTSC:
 365        case WW_BG:
 366        case WW_DK:
 367        case WW_EIAJ:
 368        case WW_I2SPT:
 369        case WW_FM:
 370        case WW_I2SADC:
 371        case WW_M:
 372                dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
 373                set_audio_registers(core, nicam_bgdki_common);
 374                set_audio_registers(core, nicam_default);
 375                break;
 376        }
 377
 378        mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
 379        set_audio_finish(core, mode);
 380}
 381
 382static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
 383{
 384        static const struct rlist a2_bgdk_common[] = {
 385                {AUD_ERRLOGPERIOD_R, 0x00000064},
 386                {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
 387                {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
 388                {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
 389                {AUD_PDF_DDS_CNST_BYTE2, 0x06},
 390                {AUD_PDF_DDS_CNST_BYTE1, 0x82},
 391                {AUD_PDF_DDS_CNST_BYTE0, 0x12},
 392                {AUD_QAM_MODE, 0x05},
 393                {AUD_PHACC_FREQ_8MSB, 0x34},
 394                {AUD_PHACC_FREQ_8LSB, 0x4c},
 395                {AUD_RATE_ADJ1, 0x00000100},
 396                {AUD_RATE_ADJ2, 0x00000200},
 397                {AUD_RATE_ADJ3, 0x00000300},
 398                {AUD_RATE_ADJ4, 0x00000400},
 399                {AUD_RATE_ADJ5, 0x00000500},
 400                {AUD_THR_FR, 0x00000000},
 401                {AAGC_HYST, 0x0000001a},
 402                {AUD_PILOT_BQD_1_K0, 0x0000755b},
 403                {AUD_PILOT_BQD_1_K1, 0x00551340},
 404                {AUD_PILOT_BQD_1_K2, 0x006d30be},
 405                {AUD_PILOT_BQD_1_K3, 0xffd394af},
 406                {AUD_PILOT_BQD_1_K4, 0x00400000},
 407                {AUD_PILOT_BQD_2_K0, 0x00040000},
 408                {AUD_PILOT_BQD_2_K1, 0x002a4841},
 409                {AUD_PILOT_BQD_2_K2, 0x00400000},
 410                {AUD_PILOT_BQD_2_K3, 0x00000000},
 411                {AUD_PILOT_BQD_2_K4, 0x00000000},
 412                {AUD_MODE_CHG_TIMER, 0x00000040},
 413                {AUD_AFE_12DB_EN, 0x00000001},
 414                {AUD_CORDIC_SHIFT_0, 0x00000007},
 415                {AUD_CORDIC_SHIFT_1, 0x00000007},
 416                {AUD_DEEMPH0_G0, 0x00000380},
 417                {AUD_DEEMPH1_G0, 0x00000380},
 418                {AUD_DCOC_0_SRC, 0x0000001a},
 419                {AUD_DCOC0_SHIFT, 0x00000000},
 420                {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
 421                {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
 422                {AUD_DCOC_PASS_IN, 0x00000003},
 423                {AUD_IIR3_0_SEL, 0x00000021},
 424                {AUD_DN2_AFC, 0x00000002},
 425                {AUD_DCOC_1_SRC, 0x0000001b},
 426                {AUD_DCOC1_SHIFT, 0x00000000},
 427                {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
 428                {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
 429                {AUD_IIR3_1_SEL, 0x00000023},
 430                {AUD_RDSI_SEL, 0x00000017},
 431                {AUD_RDSI_SHIFT, 0x00000000},
 432                {AUD_RDSQ_SEL, 0x00000017},
 433                {AUD_RDSQ_SHIFT, 0x00000000},
 434                {AUD_PLL_INT, 0x0000001e},
 435                {AUD_PLL_DDS, 0x00000000},
 436                {AUD_PLL_FRAC, 0x0000e542},
 437                {AUD_POLYPH80SCALEFAC, 0x00000001},
 438                {AUD_START_TIMER, 0x00000000},
 439                { /* end of list */ },
 440        };
 441
 442        static const struct rlist a2_bg[] = {
 443                {AUD_DMD_RA_DDS, 0x002a4f2f},
 444                {AUD_C1_UP_THR, 0x00007000},
 445                {AUD_C1_LO_THR, 0x00005400},
 446                {AUD_C2_UP_THR, 0x00005400},
 447                {AUD_C2_LO_THR, 0x00003000},
 448                { /* end of list */ },
 449        };
 450
 451        static const struct rlist a2_dk[] = {
 452                {AUD_DMD_RA_DDS, 0x002a4f2f},
 453                {AUD_C1_UP_THR, 0x00007000},
 454                {AUD_C1_LO_THR, 0x00005400},
 455                {AUD_C2_UP_THR, 0x00005400},
 456                {AUD_C2_LO_THR, 0x00003000},
 457                {AUD_DN0_FREQ, 0x00003a1c},
 458                {AUD_DN2_FREQ, 0x0000d2e0},
 459                { /* end of list */ },
 460        };
 461
 462        static const struct rlist a1_i[] = {
 463                {AUD_ERRLOGPERIOD_R, 0x00000064},
 464                {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
 465                {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
 466                {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
 467                {AUD_PDF_DDS_CNST_BYTE2, 0x06},
 468                {AUD_PDF_DDS_CNST_BYTE1, 0x82},
 469                {AUD_PDF_DDS_CNST_BYTE0, 0x12},
 470                {AUD_QAM_MODE, 0x05},
 471                {AUD_PHACC_FREQ_8MSB, 0x3a},
 472                {AUD_PHACC_FREQ_8LSB, 0x93},
 473                {AUD_DMD_RA_DDS, 0x002a4f2f},
 474                {AUD_PLL_INT, 0x0000001e},
 475                {AUD_PLL_DDS, 0x00000004},
 476                {AUD_PLL_FRAC, 0x0000e542},
 477                {AUD_RATE_ADJ1, 0x00000100},
 478                {AUD_RATE_ADJ2, 0x00000200},
 479                {AUD_RATE_ADJ3, 0x00000300},
 480                {AUD_RATE_ADJ4, 0x00000400},
 481                {AUD_RATE_ADJ5, 0x00000500},
 482                {AUD_THR_FR, 0x00000000},
 483                {AUD_PILOT_BQD_1_K0, 0x0000755b},
 484                {AUD_PILOT_BQD_1_K1, 0x00551340},
 485                {AUD_PILOT_BQD_1_K2, 0x006d30be},
 486                {AUD_PILOT_BQD_1_K3, 0xffd394af},
 487                {AUD_PILOT_BQD_1_K4, 0x00400000},
 488                {AUD_PILOT_BQD_2_K0, 0x00040000},
 489                {AUD_PILOT_BQD_2_K1, 0x002a4841},
 490                {AUD_PILOT_BQD_2_K2, 0x00400000},
 491                {AUD_PILOT_BQD_2_K3, 0x00000000},
 492                {AUD_PILOT_BQD_2_K4, 0x00000000},
 493                {AUD_MODE_CHG_TIMER, 0x00000060},
 494                {AUD_AFE_12DB_EN, 0x00000001},
 495                {AAGC_HYST, 0x0000000a},
 496                {AUD_CORDIC_SHIFT_0, 0x00000007},
 497                {AUD_CORDIC_SHIFT_1, 0x00000007},
 498                {AUD_C1_UP_THR, 0x00007000},
 499                {AUD_C1_LO_THR, 0x00005400},
 500                {AUD_C2_UP_THR, 0x00005400},
 501                {AUD_C2_LO_THR, 0x00003000},
 502                {AUD_DCOC_0_SRC, 0x0000001a},
 503                {AUD_DCOC0_SHIFT, 0x00000000},
 504                {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
 505                {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
 506                {AUD_DCOC_PASS_IN, 0x00000003},
 507                {AUD_IIR3_0_SEL, 0x00000021},
 508                {AUD_DN2_AFC, 0x00000002},
 509                {AUD_DCOC_1_SRC, 0x0000001b},
 510                {AUD_DCOC1_SHIFT, 0x00000000},
 511                {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
 512                {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
 513                {AUD_IIR3_1_SEL, 0x00000023},
 514                {AUD_DN0_FREQ, 0x000035a3},
 515                {AUD_DN2_FREQ, 0x000029c7},
 516                {AUD_CRDC0_SRC_SEL, 0x00000511},
 517                {AUD_IIR1_0_SEL, 0x00000001},
 518                {AUD_IIR1_1_SEL, 0x00000000},
 519                {AUD_IIR3_2_SEL, 0x00000003},
 520                {AUD_IIR3_2_SHIFT, 0x00000000},
 521                {AUD_IIR3_0_SEL, 0x00000002},
 522                {AUD_IIR2_0_SEL, 0x00000021},
 523                {AUD_IIR2_0_SHIFT, 0x00000002},
 524                {AUD_DEEMPH0_SRC_SEL, 0x0000000b},
 525                {AUD_DEEMPH1_SRC_SEL, 0x0000000b},
 526                {AUD_POLYPH80SCALEFAC, 0x00000001},
 527                {AUD_START_TIMER, 0x00000000},
 528                { /* end of list */ },
 529        };
 530
 531        static const struct rlist am_l[] = {
 532                {AUD_ERRLOGPERIOD_R, 0x00000064},
 533                {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
 534                {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
 535                {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
 536                {AUD_PDF_DDS_CNST_BYTE2, 0x48},
 537                {AUD_PDF_DDS_CNST_BYTE1, 0x3D},
 538                {AUD_QAM_MODE, 0x00},
 539                {AUD_PDF_DDS_CNST_BYTE0, 0xf5},
 540                {AUD_PHACC_FREQ_8MSB, 0x3a},
 541                {AUD_PHACC_FREQ_8LSB, 0x4a},
 542                {AUD_DEEMPHGAIN_R, 0x00006680},
 543                {AUD_DEEMPHNUMER1_R, 0x000353DE},
 544                {AUD_DEEMPHNUMER2_R, 0x000001B1},
 545                {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
 546                {AUD_DEEMPHDENOM2_R, 0x00000000},
 547                {AUD_FM_MODE_ENABLE, 0x00000007},
 548                {AUD_POLYPH80SCALEFAC, 0x00000003},
 549                {AUD_AFE_12DB_EN, 0x00000001},
 550                {AAGC_GAIN, 0x00000000},
 551                {AAGC_HYST, 0x00000018},
 552                {AAGC_DEF, 0x00000020},
 553                {AUD_DN0_FREQ, 0x00000000},
 554                {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
 555                {AUD_DCOC_0_SRC, 0x00000021},
 556                {AUD_IIR1_0_SEL, 0x00000000},
 557                {AUD_IIR1_0_SHIFT, 0x00000007},
 558                {AUD_IIR1_1_SEL, 0x00000002},
 559                {AUD_IIR1_1_SHIFT, 0x00000000},
 560                {AUD_DCOC_1_SRC, 0x00000003},
 561                {AUD_DCOC1_SHIFT, 0x00000000},
 562                {AUD_DCOC_PASS_IN, 0x00000000},
 563                {AUD_IIR1_2_SEL, 0x00000023},
 564                {AUD_IIR1_2_SHIFT, 0x00000000},
 565                {AUD_IIR1_3_SEL, 0x00000004},
 566                {AUD_IIR1_3_SHIFT, 0x00000007},
 567                {AUD_IIR1_4_SEL, 0x00000005},
 568                {AUD_IIR1_4_SHIFT, 0x00000007},
 569                {AUD_IIR3_0_SEL, 0x00000007},
 570                {AUD_IIR3_0_SHIFT, 0x00000000},
 571                {AUD_DEEMPH0_SRC_SEL, 0x00000011},
 572                {AUD_DEEMPH0_SHIFT, 0x00000000},
 573                {AUD_DEEMPH0_G0, 0x00007000},
 574                {AUD_DEEMPH0_A0, 0x00000000},
 575                {AUD_DEEMPH0_B0, 0x00000000},
 576                {AUD_DEEMPH0_A1, 0x00000000},
 577                {AUD_DEEMPH0_B1, 0x00000000},
 578                {AUD_DEEMPH1_SRC_SEL, 0x00000011},
 579                {AUD_DEEMPH1_SHIFT, 0x00000000},
 580                {AUD_DEEMPH1_G0, 0x00007000},
 581                {AUD_DEEMPH1_A0, 0x00000000},
 582                {AUD_DEEMPH1_B0, 0x00000000},
 583                {AUD_DEEMPH1_A1, 0x00000000},
 584                {AUD_DEEMPH1_B1, 0x00000000},
 585                {AUD_OUT0_SEL, 0x0000003F},
 586                {AUD_OUT1_SEL, 0x0000003F},
 587                {AUD_DMD_RA_DDS, 0x00F5C285},
 588                {AUD_PLL_INT, 0x0000001E},
 589                {AUD_PLL_DDS, 0x00000000},
 590                {AUD_PLL_FRAC, 0x0000E542},
 591                {AUD_RATE_ADJ1, 0x00000100},
 592                {AUD_RATE_ADJ2, 0x00000200},
 593                {AUD_RATE_ADJ3, 0x00000300},
 594                {AUD_RATE_ADJ4, 0x00000400},
 595                {AUD_RATE_ADJ5, 0x00000500},
 596                {AUD_RATE_THRES_DMD, 0x000000C0},
 597                { /* end of list */ },
 598        };
 599
 600        static const struct rlist a2_deemph50[] = {
 601                {AUD_DEEMPH0_G0, 0x00000380},
 602                {AUD_DEEMPH1_G0, 0x00000380},
 603                {AUD_DEEMPHGAIN_R, 0x000011e1},
 604                {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
 605                {AUD_DEEMPHNUMER2_R, 0x0003023c},
 606                { /* end of list */ },
 607        };
 608
 609        set_audio_start(core, SEL_A2);
 610        switch (core->tvaudio) {
 611        case WW_BG:
 612                dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__);
 613                set_audio_registers(core, a2_bgdk_common);
 614                set_audio_registers(core, a2_bg);
 615                set_audio_registers(core, a2_deemph50);
 616                break;
 617        case WW_DK:
 618                dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__);
 619                set_audio_registers(core, a2_bgdk_common);
 620                set_audio_registers(core, a2_dk);
 621                set_audio_registers(core, a2_deemph50);
 622                break;
 623        case WW_I:
 624                dprintk("%s PAL-I A1 (status: known-good)\n", __func__);
 625                set_audio_registers(core, a1_i);
 626                set_audio_registers(core, a2_deemph50);
 627                break;
 628        case WW_L:
 629                dprintk("%s AM-L (status: devel)\n", __func__);
 630                set_audio_registers(core, am_l);
 631                break;
 632        case WW_NONE:
 633        case WW_BTSC:
 634        case WW_EIAJ:
 635        case WW_I2SPT:
 636        case WW_FM:
 637        case WW_I2SADC:
 638        case WW_M:
 639                dprintk("%s Warning: wrong value\n", __func__);
 640                return;
 641                break;
 642        }
 643
 644        mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF;
 645        set_audio_finish(core, mode);
 646}
 647
 648static void set_audio_standard_EIAJ(struct cx88_core *core)
 649{
 650        static const struct rlist eiaj[] = {
 651                /* TODO: eiaj register settings are not there yet ... */
 652
 653                { /* end of list */ },
 654        };
 655        dprintk("%s (status: unknown)\n", __func__);
 656
 657        set_audio_start(core, SEL_EIAJ);
 658        set_audio_registers(core, eiaj);
 659        set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
 660}
 661
 662static void set_audio_standard_FM(struct cx88_core *core,
 663                                  enum cx88_deemph_type deemph)
 664{
 665        static const struct rlist fm_deemph_50[] = {
 666                {AUD_DEEMPH0_G0, 0x0C45},
 667                {AUD_DEEMPH0_A0, 0x6262},
 668                {AUD_DEEMPH0_B0, 0x1C29},
 669                {AUD_DEEMPH0_A1, 0x3FC66},
 670                {AUD_DEEMPH0_B1, 0x399A},
 671
 672                {AUD_DEEMPH1_G0, 0x0D80},
 673                {AUD_DEEMPH1_A0, 0x6262},
 674                {AUD_DEEMPH1_B0, 0x1C29},
 675                {AUD_DEEMPH1_A1, 0x3FC66},
 676                {AUD_DEEMPH1_B1, 0x399A},
 677
 678                {AUD_POLYPH80SCALEFAC, 0x0003},
 679                { /* end of list */ },
 680        };
 681        static const struct rlist fm_deemph_75[] = {
 682                {AUD_DEEMPH0_G0, 0x091B},
 683                {AUD_DEEMPH0_A0, 0x6B68},
 684                {AUD_DEEMPH0_B0, 0x11EC},
 685                {AUD_DEEMPH0_A1, 0x3FC66},
 686                {AUD_DEEMPH0_B1, 0x399A},
 687
 688                {AUD_DEEMPH1_G0, 0x0AA0},
 689                {AUD_DEEMPH1_A0, 0x6B68},
 690                {AUD_DEEMPH1_B0, 0x11EC},
 691                {AUD_DEEMPH1_A1, 0x3FC66},
 692                {AUD_DEEMPH1_B1, 0x399A},
 693
 694                {AUD_POLYPH80SCALEFAC, 0x0003},
 695                { /* end of list */ },
 696        };
 697
 698        /* It is enough to leave default values? */
 699        /* No, it's not!  The deemphasis registers are reset to the 75us
 700         * values by default.  Analyzing the spectrum of the decoded audio
 701         * reveals that "no deemphasis" is the same as 75 us, while the 50 us
 702         * setting results in less deemphasis.  */
 703        static const struct rlist fm_no_deemph[] = {
 704
 705                {AUD_POLYPH80SCALEFAC, 0x0003},
 706                { /* end of list */ },
 707        };
 708
 709        dprintk("%s (status: unknown)\n", __func__);
 710        set_audio_start(core, SEL_FMRADIO);
 711
 712        switch (deemph) {
 713        default:
 714        case FM_NO_DEEMPH:
 715                set_audio_registers(core, fm_no_deemph);
 716                break;
 717
 718        case FM_DEEMPH_50:
 719                set_audio_registers(core, fm_deemph_50);
 720                break;
 721
 722        case FM_DEEMPH_75:
 723                set_audio_registers(core, fm_deemph_75);
 724                break;
 725        }
 726
 727        set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
 728}
 729
 730/* ----------------------------------------------------------- */
 731
 732static int cx88_detect_nicam(struct cx88_core *core)
 733{
 734        int i, j = 0;
 735
 736        dprintk("start nicam autodetect.\n");
 737
 738        for (i = 0; i < 6; i++) {
 739                /* if bit1=1 then nicam is detected */
 740                j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
 741
 742                if (j == 1) {
 743                        dprintk("nicam is detected.\n");
 744                        return 1;
 745                }
 746
 747                /* wait a little bit for next reading status */
 748                msleep(10);
 749        }
 750
 751        dprintk("nicam is not detected.\n");
 752        return 0;
 753}
 754
 755void cx88_set_tvaudio(struct cx88_core *core)
 756{
 757        switch (core->tvaudio) {
 758        case WW_BTSC:
 759                set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
 760                break;
 761        case WW_BG:
 762        case WW_DK:
 763        case WW_M:
 764        case WW_I:
 765        case WW_L:
 766                /* prepare all dsp registers */
 767                set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
 768
 769                /* set nicam mode - otherwise
 770                   AUD_NICAM_STATUS2 contains wrong values */
 771                set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
 772                if (0 == cx88_detect_nicam(core)) {
 773                        /* fall back to fm / am mono */
 774                        set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
 775                        core->audiomode_current = V4L2_TUNER_MODE_MONO;
 776                        core->use_nicam = 0;
 777                } else {
 778                        core->use_nicam = 1;
 779                }
 780                break;
 781        case WW_EIAJ:
 782                set_audio_standard_EIAJ(core);
 783                break;
 784        case WW_FM:
 785                set_audio_standard_FM(core, radio_deemphasis);
 786                break;
 787        case WW_I2SADC:
 788                set_audio_start(core, 0x01);
 789                /*
 790                 * Slave/Philips/Autobaud
 791                 * NB on Nova-S bit1 NPhilipsSony appears to be inverted:
 792                 *      0= Sony, 1=Philips
 793                 */
 794                cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl);
 795                /* Switch to "I2S ADC mode" */
 796                cx_write(AUD_I2SCNTL, 0x1);
 797                set_audio_finish(core, EN_I2SIN_ENABLE);
 798                break;
 799        case WW_NONE:
 800        case WW_I2SPT:
 801                printk("%s/0: unknown tv audio mode [%d]\n",
 802                       core->name, core->tvaudio);
 803                break;
 804        }
 805        return;
 806}
 807
 808void cx88_newstation(struct cx88_core *core)
 809{
 810        core->audiomode_manual = UNSET;
 811        core->last_change = jiffies;
 812}
 813
 814void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 815{
 816        static const char * const m[] = { "stereo", "dual mono", "mono", "sap" };
 817        static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
 818        u32 reg, mode, pilot;
 819
 820        reg = cx_read(AUD_STATUS);
 821        mode = reg & 0x03;
 822        pilot = (reg >> 2) & 0x03;
 823
 824        if (core->astat != reg)
 825                dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
 826                        reg, m[mode], p[pilot],
 827                        aud_ctl_names[cx_read(AUD_CTL) & 63]);
 828        core->astat = reg;
 829
 830        t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
 831            V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
 832        t->rxsubchans = UNSET;
 833        t->audmode = V4L2_TUNER_MODE_MONO;
 834
 835        switch (mode) {
 836        case 0:
 837                t->audmode = V4L2_TUNER_MODE_STEREO;
 838                break;
 839        case 1:
 840                t->audmode = V4L2_TUNER_MODE_LANG2;
 841                break;
 842        case 2:
 843                t->audmode = V4L2_TUNER_MODE_MONO;
 844                break;
 845        case 3:
 846                t->audmode = V4L2_TUNER_MODE_SAP;
 847                break;
 848        }
 849
 850        switch (core->tvaudio) {
 851        case WW_BTSC:
 852        case WW_BG:
 853        case WW_DK:
 854        case WW_M:
 855        case WW_EIAJ:
 856                if (!core->use_nicam) {
 857                        t->rxsubchans = cx88_dsp_detect_stereo_sap(core);
 858                        break;
 859                }
 860                break;
 861        case WW_NONE:
 862        case WW_I:
 863        case WW_L:
 864        case WW_I2SPT:
 865        case WW_FM:
 866        case WW_I2SADC:
 867                /* nothing */
 868                break;
 869        }
 870
 871        /* If software stereo detection is not supported... */
 872        if (UNSET == t->rxsubchans) {
 873                t->rxsubchans = V4L2_TUNER_SUB_MONO;
 874                /* If the hardware itself detected stereo, also return
 875                   stereo as an available subchannel */
 876                if (V4L2_TUNER_MODE_STEREO == t->audmode)
 877                        t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
 878        }
 879        return;
 880}
 881
 882void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
 883{
 884        u32 ctl = UNSET;
 885        u32 mask = UNSET;
 886
 887        if (manual) {
 888                core->audiomode_manual = mode;
 889        } else {
 890                if (UNSET != core->audiomode_manual)
 891                        return;
 892        }
 893        core->audiomode_current = mode;
 894
 895        switch (core->tvaudio) {
 896        case WW_BTSC:
 897                switch (mode) {
 898                case V4L2_TUNER_MODE_MONO:
 899                        set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO);
 900                        break;
 901                case V4L2_TUNER_MODE_LANG1:
 902                        set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
 903                        break;
 904                case V4L2_TUNER_MODE_LANG2:
 905                        set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP);
 906                        break;
 907                case V4L2_TUNER_MODE_STEREO:
 908                case V4L2_TUNER_MODE_LANG1_LANG2:
 909                        set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO);
 910                        break;
 911                }
 912                break;
 913        case WW_BG:
 914        case WW_DK:
 915        case WW_M:
 916        case WW_I:
 917        case WW_L:
 918                if (1 == core->use_nicam) {
 919                        switch (mode) {
 920                        case V4L2_TUNER_MODE_MONO:
 921                        case V4L2_TUNER_MODE_LANG1:
 922                                set_audio_standard_NICAM(core,
 923                                                         EN_NICAM_FORCE_MONO1);
 924                                break;
 925                        case V4L2_TUNER_MODE_LANG2:
 926                                set_audio_standard_NICAM(core,
 927                                                         EN_NICAM_FORCE_MONO2);
 928                                break;
 929                        case V4L2_TUNER_MODE_STEREO:
 930                        case V4L2_TUNER_MODE_LANG1_LANG2:
 931                                set_audio_standard_NICAM(core,
 932                                                         EN_NICAM_FORCE_STEREO);
 933                                break;
 934                        }
 935                } else {
 936                        if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) {
 937                                /* fall back to fm / am mono */
 938                                set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
 939                        } else {
 940                                /* TODO: Add A2 autodection */
 941                                mask = 0x3f;
 942                                switch (mode) {
 943                                case V4L2_TUNER_MODE_MONO:
 944                                case V4L2_TUNER_MODE_LANG1:
 945                                        ctl = EN_A2_FORCE_MONO1;
 946                                        break;
 947                                case V4L2_TUNER_MODE_LANG2:
 948                                        ctl = EN_A2_FORCE_MONO2;
 949                                        break;
 950                                case V4L2_TUNER_MODE_STEREO:
 951                                case V4L2_TUNER_MODE_LANG1_LANG2:
 952                                        ctl = EN_A2_FORCE_STEREO;
 953                                        break;
 954                                }
 955                        }
 956                }
 957                break;
 958        case WW_FM:
 959                switch (mode) {
 960                case V4L2_TUNER_MODE_MONO:
 961                        ctl = EN_FMRADIO_FORCE_MONO;
 962                        mask = 0x3f;
 963                        break;
 964                case V4L2_TUNER_MODE_STEREO:
 965                        ctl = EN_FMRADIO_AUTO_STEREO;
 966                        mask = 0x3f;
 967                        break;
 968                }
 969                break;
 970        case WW_I2SADC:
 971        case WW_NONE:
 972        case WW_EIAJ:
 973        case WW_I2SPT:
 974                /* DO NOTHING */
 975                break;
 976        }
 977
 978        if (UNSET != ctl) {
 979                dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
 980                        "[status=0x%x,ctl=0x%x,vol=0x%x]\n",
 981                        mask, ctl, cx_read(AUD_STATUS),
 982                        cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
 983                cx_andor(AUD_CTL, mask, ctl);
 984        }
 985        return;
 986}
 987
 988int cx88_audio_thread(void *data)
 989{
 990        struct cx88_core *core = data;
 991        struct v4l2_tuner t;
 992        u32 mode = 0;
 993
 994        dprintk("cx88: tvaudio thread started\n");
 995        set_freezable();
 996        for (;;) {
 997                msleep_interruptible(1000);
 998                if (kthread_should_stop())
 999                        break;
1000                try_to_freeze();
1001
1002                switch (core->tvaudio) {
1003                case WW_BG:
1004                case WW_DK:
1005                case WW_M:
1006                case WW_I:
1007                case WW_L:
1008                        if (core->use_nicam)
1009                                goto hw_autodetect;
1010
1011                        /* just monitor the audio status for now ... */
1012                        memset(&t, 0, sizeof(t));
1013                        cx88_get_stereo(core, &t);
1014
1015                        if (UNSET != core->audiomode_manual)
1016                                /* manually set, don't do anything. */
1017                                continue;
1018
1019                        /* monitor signal and set stereo if available */
1020                        if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
1021                                mode = V4L2_TUNER_MODE_STEREO;
1022                        else
1023                                mode = V4L2_TUNER_MODE_MONO;
1024                        if (mode == core->audiomode_current)
1025                                continue;
1026                        /* automatically switch to best available mode */
1027                        cx88_set_stereo(core, mode, 0);
1028                        break;
1029                case WW_NONE:
1030                case WW_BTSC:
1031                case WW_EIAJ:
1032                case WW_I2SPT:
1033                case WW_FM:
1034                case WW_I2SADC:
1035hw_autodetect:
1036                        /* stereo autodetection is supported by hardware so
1037                           we don't need to do it manually. Do nothing. */
1038                        break;
1039                }
1040        }
1041
1042        dprintk("cx88: tvaudio thread exiting\n");
1043        return 0;
1044}
1045
1046/* ----------------------------------------------------------- */
1047
1048EXPORT_SYMBOL(cx88_set_tvaudio);
1049EXPORT_SYMBOL(cx88_newstation);
1050EXPORT_SYMBOL(cx88_set_stereo);
1051EXPORT_SYMBOL(cx88_get_stereo);
1052EXPORT_SYMBOL(cx88_audio_thread);
1053