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