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