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