cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cx88-tvaudio.c (28349B)


      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);