18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version]
68c2ecf20Sopenharmony_ci *  (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
78c2ecf20Sopenharmony_ci *  (c) 2003 Gerd Knorr <kraxel@bytesex.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * -----------------------------------------------------------------------
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Lot of voodoo here.  Even the data sheet doesn't help to
128c2ecf20Sopenharmony_ci * understand what is going on here, the documentation for the audio
138c2ecf20Sopenharmony_ci * part of the cx2388x chip is *very* bad.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Some of this comes from party done linux driver sources I got from
168c2ecf20Sopenharmony_ci * [undocumented].
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Some comes from the dscaler sources, one of the dscaler driver guy works
198c2ecf20Sopenharmony_ci * for Conexant ...
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * -----------------------------------------------------------------------
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "cx88.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/module.h>
278c2ecf20Sopenharmony_ci#include <linux/errno.h>
288c2ecf20Sopenharmony_ci#include <linux/freezer.h>
298c2ecf20Sopenharmony_ci#include <linux/kernel.h>
308c2ecf20Sopenharmony_ci#include <linux/mm.h>
318c2ecf20Sopenharmony_ci#include <linux/poll.h>
328c2ecf20Sopenharmony_ci#include <linux/signal.h>
338c2ecf20Sopenharmony_ci#include <linux/ioport.h>
348c2ecf20Sopenharmony_ci#include <linux/types.h>
358c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
368c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
378c2ecf20Sopenharmony_ci#include <linux/init.h>
388c2ecf20Sopenharmony_ci#include <linux/delay.h>
398c2ecf20Sopenharmony_ci#include <linux/kthread.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic unsigned int audio_debug;
428c2ecf20Sopenharmony_cimodule_param(audio_debug, int, 0644);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic unsigned int always_analog;
468c2ecf20Sopenharmony_cimodule_param(always_analog, int, 0644);
478c2ecf20Sopenharmony_ciMODULE_PARM_DESC(always_analog, "force analog audio out");
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic unsigned int radio_deemphasis;
508c2ecf20Sopenharmony_cimodule_param(radio_deemphasis, int, 0644);
518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(radio_deemphasis,
528c2ecf20Sopenharmony_ci		 "Radio deemphasis time constant, 0=None, 1=50us (elsewhere), 2=75us (USA)");
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do {				\
558c2ecf20Sopenharmony_ci	if (audio_debug)						\
568c2ecf20Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("%s: tvaudio:" fmt),		\
578c2ecf20Sopenharmony_ci			__func__, ##arg);				\
588c2ecf20Sopenharmony_ci} while (0)
598c2ecf20Sopenharmony_ci/* ----------------------------------------------------------- */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const char * const aud_ctl_names[64] = {
628c2ecf20Sopenharmony_ci	[EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
638c2ecf20Sopenharmony_ci	[EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
648c2ecf20Sopenharmony_ci	[EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
658c2ecf20Sopenharmony_ci	[EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
668c2ecf20Sopenharmony_ci	[EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
678c2ecf20Sopenharmony_ci	[EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
688c2ecf20Sopenharmony_ci	[EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
698c2ecf20Sopenharmony_ci	[EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
708c2ecf20Sopenharmony_ci	[EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
718c2ecf20Sopenharmony_ci	[EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
728c2ecf20Sopenharmony_ci	[EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
738c2ecf20Sopenharmony_ci	[EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
748c2ecf20Sopenharmony_ci	[EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
758c2ecf20Sopenharmony_ci	[EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
768c2ecf20Sopenharmony_ci	[EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
778c2ecf20Sopenharmony_ci	[EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
788c2ecf20Sopenharmony_ci	[EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
798c2ecf20Sopenharmony_ci	[EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
808c2ecf20Sopenharmony_ci	[EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
818c2ecf20Sopenharmony_ci	[EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
828c2ecf20Sopenharmony_ci	[EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
838c2ecf20Sopenharmony_ci	[EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
848c2ecf20Sopenharmony_ci	[EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct rlist {
888c2ecf20Sopenharmony_ci	u32 reg;
898c2ecf20Sopenharmony_ci	u32 val;
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void set_audio_registers(struct cx88_core *core, const struct rlist *l)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	int i;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	for (i = 0; l[i].reg; i++) {
978c2ecf20Sopenharmony_ci		switch (l[i].reg) {
988c2ecf20Sopenharmony_ci		case AUD_PDF_DDS_CNST_BYTE2:
998c2ecf20Sopenharmony_ci		case AUD_PDF_DDS_CNST_BYTE1:
1008c2ecf20Sopenharmony_ci		case AUD_PDF_DDS_CNST_BYTE0:
1018c2ecf20Sopenharmony_ci		case AUD_QAM_MODE:
1028c2ecf20Sopenharmony_ci		case AUD_PHACC_FREQ_8MSB:
1038c2ecf20Sopenharmony_ci		case AUD_PHACC_FREQ_8LSB:
1048c2ecf20Sopenharmony_ci			cx_writeb(l[i].reg, l[i].val);
1058c2ecf20Sopenharmony_ci			break;
1068c2ecf20Sopenharmony_ci		default:
1078c2ecf20Sopenharmony_ci			cx_write(l[i].reg, l[i].val);
1088c2ecf20Sopenharmony_ci			break;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void set_audio_start(struct cx88_core *core, u32 mode)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	/* mute */
1168c2ecf20Sopenharmony_ci	cx_write(AUD_VOL_CTL, (1 << 6));
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* start programming */
1198c2ecf20Sopenharmony_ci	cx_write(AUD_INIT, mode);
1208c2ecf20Sopenharmony_ci	cx_write(AUD_INIT_LD, 0x0001);
1218c2ecf20Sopenharmony_ci	cx_write(AUD_SOFT_RESET, 0x0001);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void set_audio_finish(struct cx88_core *core, u32 ctl)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	u32 volume;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* restart dma; This avoids buzz in NICAM and is good in others  */
1298c2ecf20Sopenharmony_ci	cx88_stop_audio_dma(core);
1308c2ecf20Sopenharmony_ci	cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
1318c2ecf20Sopenharmony_ci	cx88_start_audio_dma(core);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
1348c2ecf20Sopenharmony_ci		cx_write(AUD_I2SINPUTCNTL, 4);
1358c2ecf20Sopenharmony_ci		cx_write(AUD_BAUDRATE, 1);
1368c2ecf20Sopenharmony_ci		/*
1378c2ecf20Sopenharmony_ci		 * 'pass-thru mode': this enables the i2s
1388c2ecf20Sopenharmony_ci		 * output to the mpeg encoder
1398c2ecf20Sopenharmony_ci		 */
1408c2ecf20Sopenharmony_ci		cx_set(AUD_CTL, EN_I2SOUT_ENABLE);
1418c2ecf20Sopenharmony_ci		cx_write(AUD_I2SOUTPUTCNTL, 1);
1428c2ecf20Sopenharmony_ci		cx_write(AUD_I2SCNTL, 0);
1438c2ecf20Sopenharmony_ci		/* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) {
1468c2ecf20Sopenharmony_ci		ctl |= EN_DAC_ENABLE;
1478c2ecf20Sopenharmony_ci		cx_write(AUD_CTL, ctl);
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* finish programming */
1518c2ecf20Sopenharmony_ci	cx_write(AUD_SOFT_RESET, 0x0000);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* unmute */
1548c2ecf20Sopenharmony_ci	volume = cx_sread(SHADOW_AUD_VOL_CTL);
1558c2ecf20Sopenharmony_ci	cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	core->last_change = jiffies;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/* ----------------------------------------------------------- */
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
1638c2ecf20Sopenharmony_ci				    u32 mode)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	static const struct rlist btsc[] = {
1668c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
1678c2ecf20Sopenharmony_ci		{AUD_OUT1_SEL, 0x00000013},
1688c2ecf20Sopenharmony_ci		{AUD_OUT1_SHIFT, 0x00000000},
1698c2ecf20Sopenharmony_ci		{AUD_POLY0_DDS_CONSTANT, 0x0012010c},
1708c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x00c3e7aa},
1718c2ecf20Sopenharmony_ci		{AUD_DBX_IN_GAIN, 0x00004734},
1728c2ecf20Sopenharmony_ci		{AUD_DBX_WBE_GAIN, 0x00004640},
1738c2ecf20Sopenharmony_ci		{AUD_DBX_SE_GAIN, 0x00008d31},
1748c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SRC, 0x0000001a},
1758c2ecf20Sopenharmony_ci		{AUD_IIR1_4_SEL, 0x00000021},
1768c2ecf20Sopenharmony_ci		{AUD_DCOC_PASS_IN, 0x00000003},
1778c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
1788c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
1798c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
1808c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
1818c2ecf20Sopenharmony_ci		{AUD_DN0_FREQ, 0x0000283b},
1828c2ecf20Sopenharmony_ci		{AUD_DN2_SRC_SEL, 0x00000008},
1838c2ecf20Sopenharmony_ci		{AUD_DN2_FREQ, 0x00003000},
1848c2ecf20Sopenharmony_ci		{AUD_DN2_AFC, 0x00000002},
1858c2ecf20Sopenharmony_ci		{AUD_DN2_SHFT, 0x00000000},
1868c2ecf20Sopenharmony_ci		{AUD_IIR2_2_SEL, 0x00000020},
1878c2ecf20Sopenharmony_ci		{AUD_IIR2_2_SHIFT, 0x00000000},
1888c2ecf20Sopenharmony_ci		{AUD_IIR2_3_SEL, 0x0000001f},
1898c2ecf20Sopenharmony_ci		{AUD_IIR2_3_SHIFT, 0x00000000},
1908c2ecf20Sopenharmony_ci		{AUD_CRDC1_SRC_SEL, 0x000003ce},
1918c2ecf20Sopenharmony_ci		{AUD_CRDC1_SHIFT, 0x00000000},
1928c2ecf20Sopenharmony_ci		{AUD_CORDIC_SHIFT_1, 0x00000007},
1938c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SRC, 0x0000001b},
1948c2ecf20Sopenharmony_ci		{AUD_DCOC1_SHIFT, 0x00000000},
1958c2ecf20Sopenharmony_ci		{AUD_RDSI_SEL, 0x00000008},
1968c2ecf20Sopenharmony_ci		{AUD_RDSQ_SEL, 0x00000008},
1978c2ecf20Sopenharmony_ci		{AUD_RDSI_SHIFT, 0x00000000},
1988c2ecf20Sopenharmony_ci		{AUD_RDSQ_SHIFT, 0x00000000},
1998c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000003},
2008c2ecf20Sopenharmony_ci		{ /* end of list */ },
2018c2ecf20Sopenharmony_ci	};
2028c2ecf20Sopenharmony_ci	static const struct rlist btsc_sap[] = {
2038c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
2048c2ecf20Sopenharmony_ci		{AUD_DBX_IN_GAIN, 0x00007200},
2058c2ecf20Sopenharmony_ci		{AUD_DBX_WBE_GAIN, 0x00006200},
2068c2ecf20Sopenharmony_ci		{AUD_DBX_SE_GAIN, 0x00006200},
2078c2ecf20Sopenharmony_ci		{AUD_IIR1_1_SEL, 0x00000000},
2088c2ecf20Sopenharmony_ci		{AUD_IIR1_3_SEL, 0x00000001},
2098c2ecf20Sopenharmony_ci		{AUD_DN1_SRC_SEL, 0x00000007},
2108c2ecf20Sopenharmony_ci		{AUD_IIR1_4_SHIFT, 0x00000006},
2118c2ecf20Sopenharmony_ci		{AUD_IIR2_1_SHIFT, 0x00000000},
2128c2ecf20Sopenharmony_ci		{AUD_IIR2_2_SHIFT, 0x00000000},
2138c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SHIFT, 0x00000000},
2148c2ecf20Sopenharmony_ci		{AUD_IIR3_1_SHIFT, 0x00000000},
2158c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SEL, 0x0000000d},
2168c2ecf20Sopenharmony_ci		{AUD_IIR3_1_SEL, 0x0000000e},
2178c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_SRC_SEL, 0x00000014},
2188c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_SHIFT, 0x00000000},
2198c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_G0, 0x00004000},
2208c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A0, 0x00000000},
2218c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B0, 0x00000000},
2228c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A1, 0x00000000},
2238c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B1, 0x00000000},
2248c2ecf20Sopenharmony_ci		{AUD_OUT0_SEL, 0x0000003f},
2258c2ecf20Sopenharmony_ci		{AUD_OUT1_SEL, 0x0000003f},
2268c2ecf20Sopenharmony_ci		{AUD_DN1_AFC, 0x00000002},
2278c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
2288c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
2298c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
2308c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
2318c2ecf20Sopenharmony_ci		{AUD_IIR1_0_SEL, 0x0000001d},
2328c2ecf20Sopenharmony_ci		{AUD_IIR1_2_SEL, 0x0000001e},
2338c2ecf20Sopenharmony_ci		{AUD_IIR2_1_SEL, 0x00000002},
2348c2ecf20Sopenharmony_ci		{AUD_IIR2_2_SEL, 0x00000004},
2358c2ecf20Sopenharmony_ci		{AUD_IIR3_2_SEL, 0x0000000f},
2368c2ecf20Sopenharmony_ci		{AUD_DCOC2_SHIFT, 0x00000001},
2378c2ecf20Sopenharmony_ci		{AUD_IIR3_2_SHIFT, 0x00000001},
2388c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_SRC_SEL, 0x00000014},
2398c2ecf20Sopenharmony_ci		{AUD_CORDIC_SHIFT_1, 0x00000006},
2408c2ecf20Sopenharmony_ci		{AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
2418c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x00f696e6},
2428c2ecf20Sopenharmony_ci		{AUD_IIR2_3_SEL, 0x00000025},
2438c2ecf20Sopenharmony_ci		{AUD_IIR1_4_SEL, 0x00000021},
2448c2ecf20Sopenharmony_ci		{AUD_DN1_FREQ, 0x0000c965},
2458c2ecf20Sopenharmony_ci		{AUD_DCOC_PASS_IN, 0x00000003},
2468c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SRC, 0x0000001a},
2478c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SRC, 0x0000001b},
2488c2ecf20Sopenharmony_ci		{AUD_DCOC1_SHIFT, 0x00000000},
2498c2ecf20Sopenharmony_ci		{AUD_RDSI_SEL, 0x00000009},
2508c2ecf20Sopenharmony_ci		{AUD_RDSQ_SEL, 0x00000009},
2518c2ecf20Sopenharmony_ci		{AUD_RDSI_SHIFT, 0x00000000},
2528c2ecf20Sopenharmony_ci		{AUD_RDSQ_SHIFT, 0x00000000},
2538c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000003},
2548c2ecf20Sopenharmony_ci		{ /* end of list */ },
2558c2ecf20Sopenharmony_ci	};
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	mode |= EN_FMRADIO_EN_RDS;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (sap) {
2608c2ecf20Sopenharmony_ci		dprintk("%s SAP (status: unknown)\n", __func__);
2618c2ecf20Sopenharmony_ci		set_audio_start(core, SEL_SAP);
2628c2ecf20Sopenharmony_ci		set_audio_registers(core, btsc_sap);
2638c2ecf20Sopenharmony_ci		set_audio_finish(core, mode);
2648c2ecf20Sopenharmony_ci	} else {
2658c2ecf20Sopenharmony_ci		dprintk("%s (status: known-good)\n", __func__);
2668c2ecf20Sopenharmony_ci		set_audio_start(core, SEL_BTSC);
2678c2ecf20Sopenharmony_ci		set_audio_registers(core, btsc);
2688c2ecf20Sopenharmony_ci		set_audio_finish(core, mode);
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	static const struct rlist nicam_l[] = {
2758c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
2768c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ1, 0x00000060},
2778c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ2, 0x000000F9},
2788c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ3, 0x000001CC},
2798c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ4, 0x000002B3},
2808c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ5, 0x00000726},
2818c2ecf20Sopenharmony_ci		{AUD_DEEMPHDENOM1_R, 0x0000F3D0},
2828c2ecf20Sopenharmony_ci		{AUD_DEEMPHDENOM2_R, 0x00000000},
2838c2ecf20Sopenharmony_ci		{AUD_ERRLOGPERIOD_R, 0x00000064},
2848c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
2858c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
2868c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
2878c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000003},
2888c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x00C00000},
2898c2ecf20Sopenharmony_ci		{AUD_PLL_INT, 0x0000001E},
2908c2ecf20Sopenharmony_ci		{AUD_PLL_DDS, 0x00000000},
2918c2ecf20Sopenharmony_ci		{AUD_PLL_FRAC, 0x0000E542},
2928c2ecf20Sopenharmony_ci		{AUD_START_TIMER, 0x00000000},
2938c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER1_R, 0x000353DE},
2948c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER2_R, 0x000001B1},
2958c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
2968c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
2978c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
2988c2ecf20Sopenharmony_ci		{AUD_QAM_MODE, 0x05},
2998c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8MSB, 0x34},
3008c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8LSB, 0x4C},
3018c2ecf20Sopenharmony_ci		{AUD_DEEMPHGAIN_R, 0x00006680},
3028c2ecf20Sopenharmony_ci		{AUD_RATE_THRES_DMD, 0x000000C0},
3038c2ecf20Sopenharmony_ci		{ /* end of list */ },
3048c2ecf20Sopenharmony_ci	};
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	static const struct rlist nicam_bgdki_common[] = {
3078c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
3088c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ1, 0x00000010},
3098c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ2, 0x00000040},
3108c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ3, 0x00000100},
3118c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ4, 0x00000400},
3128c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ5, 0x00001000},
3138c2ecf20Sopenharmony_ci		{AUD_ERRLOGPERIOD_R, 0x00000fff},
3148c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
3158c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
3168c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
3178c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000003},
3188c2ecf20Sopenharmony_ci		{AUD_DEEMPHGAIN_R, 0x000023c2},
3198c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER1_R, 0x0002a7bc},
3208c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER2_R, 0x0003023e},
3218c2ecf20Sopenharmony_ci		{AUD_DEEMPHDENOM1_R, 0x0000f3d0},
3228c2ecf20Sopenharmony_ci		{AUD_DEEMPHDENOM2_R, 0x00000000},
3238c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
3248c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
3258c2ecf20Sopenharmony_ci		{AUD_QAM_MODE, 0x05},
3268c2ecf20Sopenharmony_ci		{ /* end of list */ },
3278c2ecf20Sopenharmony_ci	};
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	static const struct rlist nicam_i[] = {
3308c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
3318c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8MSB, 0x3a},
3328c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8LSB, 0x93},
3338c2ecf20Sopenharmony_ci		{ /* end of list */ },
3348c2ecf20Sopenharmony_ci	};
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	static const struct rlist nicam_default[] = {
3378c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE0, 0x16},
3388c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8MSB, 0x34},
3398c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8LSB, 0x4c},
3408c2ecf20Sopenharmony_ci		{ /* end of list */ },
3418c2ecf20Sopenharmony_ci	};
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	set_audio_start(core, SEL_NICAM);
3448c2ecf20Sopenharmony_ci	switch (core->tvaudio) {
3458c2ecf20Sopenharmony_ci	case WW_L:
3468c2ecf20Sopenharmony_ci		dprintk("%s SECAM-L NICAM (status: devel)\n", __func__);
3478c2ecf20Sopenharmony_ci		set_audio_registers(core, nicam_l);
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci	case WW_I:
3508c2ecf20Sopenharmony_ci		dprintk("%s PAL-I NICAM (status: known-good)\n", __func__);
3518c2ecf20Sopenharmony_ci		set_audio_registers(core, nicam_bgdki_common);
3528c2ecf20Sopenharmony_ci		set_audio_registers(core, nicam_i);
3538c2ecf20Sopenharmony_ci		break;
3548c2ecf20Sopenharmony_ci	case WW_NONE:
3558c2ecf20Sopenharmony_ci	case WW_BTSC:
3568c2ecf20Sopenharmony_ci	case WW_BG:
3578c2ecf20Sopenharmony_ci	case WW_DK:
3588c2ecf20Sopenharmony_ci	case WW_EIAJ:
3598c2ecf20Sopenharmony_ci	case WW_I2SPT:
3608c2ecf20Sopenharmony_ci	case WW_FM:
3618c2ecf20Sopenharmony_ci	case WW_I2SADC:
3628c2ecf20Sopenharmony_ci	case WW_M:
3638c2ecf20Sopenharmony_ci		dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
3648c2ecf20Sopenharmony_ci		set_audio_registers(core, nicam_bgdki_common);
3658c2ecf20Sopenharmony_ci		set_audio_registers(core, nicam_default);
3668c2ecf20Sopenharmony_ci		break;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
3708c2ecf20Sopenharmony_ci	set_audio_finish(core, mode);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void set_audio_standard_A2(struct cx88_core *core, u32 mode)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	static const struct rlist a2_bgdk_common[] = {
3768c2ecf20Sopenharmony_ci		{AUD_ERRLOGPERIOD_R, 0x00000064},
3778c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
3788c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
3798c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
3808c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
3818c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
3828c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
3838c2ecf20Sopenharmony_ci		{AUD_QAM_MODE, 0x05},
3848c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8MSB, 0x34},
3858c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8LSB, 0x4c},
3868c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ1, 0x00000100},
3878c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ2, 0x00000200},
3888c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ3, 0x00000300},
3898c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ4, 0x00000400},
3908c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ5, 0x00000500},
3918c2ecf20Sopenharmony_ci		{AUD_THR_FR, 0x00000000},
3928c2ecf20Sopenharmony_ci		{AAGC_HYST, 0x0000001a},
3938c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K0, 0x0000755b},
3948c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K1, 0x00551340},
3958c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K2, 0x006d30be},
3968c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K3, 0xffd394af},
3978c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K4, 0x00400000},
3988c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K0, 0x00040000},
3998c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K1, 0x002a4841},
4008c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K2, 0x00400000},
4018c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K3, 0x00000000},
4028c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K4, 0x00000000},
4038c2ecf20Sopenharmony_ci		{AUD_MODE_CHG_TIMER, 0x00000040},
4048c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
4058c2ecf20Sopenharmony_ci		{AUD_CORDIC_SHIFT_0, 0x00000007},
4068c2ecf20Sopenharmony_ci		{AUD_CORDIC_SHIFT_1, 0x00000007},
4078c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_G0, 0x00000380},
4088c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_G0, 0x00000380},
4098c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SRC, 0x0000001a},
4108c2ecf20Sopenharmony_ci		{AUD_DCOC0_SHIFT, 0x00000000},
4118c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
4128c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
4138c2ecf20Sopenharmony_ci		{AUD_DCOC_PASS_IN, 0x00000003},
4148c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SEL, 0x00000021},
4158c2ecf20Sopenharmony_ci		{AUD_DN2_AFC, 0x00000002},
4168c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SRC, 0x0000001b},
4178c2ecf20Sopenharmony_ci		{AUD_DCOC1_SHIFT, 0x00000000},
4188c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
4198c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
4208c2ecf20Sopenharmony_ci		{AUD_IIR3_1_SEL, 0x00000023},
4218c2ecf20Sopenharmony_ci		{AUD_RDSI_SEL, 0x00000017},
4228c2ecf20Sopenharmony_ci		{AUD_RDSI_SHIFT, 0x00000000},
4238c2ecf20Sopenharmony_ci		{AUD_RDSQ_SEL, 0x00000017},
4248c2ecf20Sopenharmony_ci		{AUD_RDSQ_SHIFT, 0x00000000},
4258c2ecf20Sopenharmony_ci		{AUD_PLL_INT, 0x0000001e},
4268c2ecf20Sopenharmony_ci		{AUD_PLL_DDS, 0x00000000},
4278c2ecf20Sopenharmony_ci		{AUD_PLL_FRAC, 0x0000e542},
4288c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000001},
4298c2ecf20Sopenharmony_ci		{AUD_START_TIMER, 0x00000000},
4308c2ecf20Sopenharmony_ci		{ /* end of list */ },
4318c2ecf20Sopenharmony_ci	};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	static const struct rlist a2_bg[] = {
4348c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x002a4f2f},
4358c2ecf20Sopenharmony_ci		{AUD_C1_UP_THR, 0x00007000},
4368c2ecf20Sopenharmony_ci		{AUD_C1_LO_THR, 0x00005400},
4378c2ecf20Sopenharmony_ci		{AUD_C2_UP_THR, 0x00005400},
4388c2ecf20Sopenharmony_ci		{AUD_C2_LO_THR, 0x00003000},
4398c2ecf20Sopenharmony_ci		{ /* end of list */ },
4408c2ecf20Sopenharmony_ci	};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	static const struct rlist a2_dk[] = {
4438c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x002a4f2f},
4448c2ecf20Sopenharmony_ci		{AUD_C1_UP_THR, 0x00007000},
4458c2ecf20Sopenharmony_ci		{AUD_C1_LO_THR, 0x00005400},
4468c2ecf20Sopenharmony_ci		{AUD_C2_UP_THR, 0x00005400},
4478c2ecf20Sopenharmony_ci		{AUD_C2_LO_THR, 0x00003000},
4488c2ecf20Sopenharmony_ci		{AUD_DN0_FREQ, 0x00003a1c},
4498c2ecf20Sopenharmony_ci		{AUD_DN2_FREQ, 0x0000d2e0},
4508c2ecf20Sopenharmony_ci		{ /* end of list */ },
4518c2ecf20Sopenharmony_ci	};
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	static const struct rlist a1_i[] = {
4548c2ecf20Sopenharmony_ci		{AUD_ERRLOGPERIOD_R, 0x00000064},
4558c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
4568c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
4578c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
4588c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE2, 0x06},
4598c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE1, 0x82},
4608c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE0, 0x12},
4618c2ecf20Sopenharmony_ci		{AUD_QAM_MODE, 0x05},
4628c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8MSB, 0x3a},
4638c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8LSB, 0x93},
4648c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x002a4f2f},
4658c2ecf20Sopenharmony_ci		{AUD_PLL_INT, 0x0000001e},
4668c2ecf20Sopenharmony_ci		{AUD_PLL_DDS, 0x00000004},
4678c2ecf20Sopenharmony_ci		{AUD_PLL_FRAC, 0x0000e542},
4688c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ1, 0x00000100},
4698c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ2, 0x00000200},
4708c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ3, 0x00000300},
4718c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ4, 0x00000400},
4728c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ5, 0x00000500},
4738c2ecf20Sopenharmony_ci		{AUD_THR_FR, 0x00000000},
4748c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K0, 0x0000755b},
4758c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K1, 0x00551340},
4768c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K2, 0x006d30be},
4778c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K3, 0xffd394af},
4788c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_1_K4, 0x00400000},
4798c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K0, 0x00040000},
4808c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K1, 0x002a4841},
4818c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K2, 0x00400000},
4828c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K3, 0x00000000},
4838c2ecf20Sopenharmony_ci		{AUD_PILOT_BQD_2_K4, 0x00000000},
4848c2ecf20Sopenharmony_ci		{AUD_MODE_CHG_TIMER, 0x00000060},
4858c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
4868c2ecf20Sopenharmony_ci		{AAGC_HYST, 0x0000000a},
4878c2ecf20Sopenharmony_ci		{AUD_CORDIC_SHIFT_0, 0x00000007},
4888c2ecf20Sopenharmony_ci		{AUD_CORDIC_SHIFT_1, 0x00000007},
4898c2ecf20Sopenharmony_ci		{AUD_C1_UP_THR, 0x00007000},
4908c2ecf20Sopenharmony_ci		{AUD_C1_LO_THR, 0x00005400},
4918c2ecf20Sopenharmony_ci		{AUD_C2_UP_THR, 0x00005400},
4928c2ecf20Sopenharmony_ci		{AUD_C2_LO_THR, 0x00003000},
4938c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SRC, 0x0000001a},
4948c2ecf20Sopenharmony_ci		{AUD_DCOC0_SHIFT, 0x00000000},
4958c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
4968c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SHIFT_IN1, 0x00000008},
4978c2ecf20Sopenharmony_ci		{AUD_DCOC_PASS_IN, 0x00000003},
4988c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SEL, 0x00000021},
4998c2ecf20Sopenharmony_ci		{AUD_DN2_AFC, 0x00000002},
5008c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SRC, 0x0000001b},
5018c2ecf20Sopenharmony_ci		{AUD_DCOC1_SHIFT, 0x00000000},
5028c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
5038c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SHIFT_IN1, 0x00000008},
5048c2ecf20Sopenharmony_ci		{AUD_IIR3_1_SEL, 0x00000023},
5058c2ecf20Sopenharmony_ci		{AUD_DN0_FREQ, 0x000035a3},
5068c2ecf20Sopenharmony_ci		{AUD_DN2_FREQ, 0x000029c7},
5078c2ecf20Sopenharmony_ci		{AUD_CRDC0_SRC_SEL, 0x00000511},
5088c2ecf20Sopenharmony_ci		{AUD_IIR1_0_SEL, 0x00000001},
5098c2ecf20Sopenharmony_ci		{AUD_IIR1_1_SEL, 0x00000000},
5108c2ecf20Sopenharmony_ci		{AUD_IIR3_2_SEL, 0x00000003},
5118c2ecf20Sopenharmony_ci		{AUD_IIR3_2_SHIFT, 0x00000000},
5128c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SEL, 0x00000002},
5138c2ecf20Sopenharmony_ci		{AUD_IIR2_0_SEL, 0x00000021},
5148c2ecf20Sopenharmony_ci		{AUD_IIR2_0_SHIFT, 0x00000002},
5158c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_SRC_SEL, 0x0000000b},
5168c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_SRC_SEL, 0x0000000b},
5178c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000001},
5188c2ecf20Sopenharmony_ci		{AUD_START_TIMER, 0x00000000},
5198c2ecf20Sopenharmony_ci		{ /* end of list */ },
5208c2ecf20Sopenharmony_ci	};
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	static const struct rlist am_l[] = {
5238c2ecf20Sopenharmony_ci		{AUD_ERRLOGPERIOD_R, 0x00000064},
5248c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
5258c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
5268c2ecf20Sopenharmony_ci		{AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
5278c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE2, 0x48},
5288c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE1, 0x3D},
5298c2ecf20Sopenharmony_ci		{AUD_QAM_MODE, 0x00},
5308c2ecf20Sopenharmony_ci		{AUD_PDF_DDS_CNST_BYTE0, 0xf5},
5318c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8MSB, 0x3a},
5328c2ecf20Sopenharmony_ci		{AUD_PHACC_FREQ_8LSB, 0x4a},
5338c2ecf20Sopenharmony_ci		{AUD_DEEMPHGAIN_R, 0x00006680},
5348c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER1_R, 0x000353DE},
5358c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER2_R, 0x000001B1},
5368c2ecf20Sopenharmony_ci		{AUD_DEEMPHDENOM1_R, 0x0000F3D0},
5378c2ecf20Sopenharmony_ci		{AUD_DEEMPHDENOM2_R, 0x00000000},
5388c2ecf20Sopenharmony_ci		{AUD_FM_MODE_ENABLE, 0x00000007},
5398c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x00000003},
5408c2ecf20Sopenharmony_ci		{AUD_AFE_12DB_EN, 0x00000001},
5418c2ecf20Sopenharmony_ci		{AAGC_GAIN, 0x00000000},
5428c2ecf20Sopenharmony_ci		{AAGC_HYST, 0x00000018},
5438c2ecf20Sopenharmony_ci		{AAGC_DEF, 0x00000020},
5448c2ecf20Sopenharmony_ci		{AUD_DN0_FREQ, 0x00000000},
5458c2ecf20Sopenharmony_ci		{AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
5468c2ecf20Sopenharmony_ci		{AUD_DCOC_0_SRC, 0x00000021},
5478c2ecf20Sopenharmony_ci		{AUD_IIR1_0_SEL, 0x00000000},
5488c2ecf20Sopenharmony_ci		{AUD_IIR1_0_SHIFT, 0x00000007},
5498c2ecf20Sopenharmony_ci		{AUD_IIR1_1_SEL, 0x00000002},
5508c2ecf20Sopenharmony_ci		{AUD_IIR1_1_SHIFT, 0x00000000},
5518c2ecf20Sopenharmony_ci		{AUD_DCOC_1_SRC, 0x00000003},
5528c2ecf20Sopenharmony_ci		{AUD_DCOC1_SHIFT, 0x00000000},
5538c2ecf20Sopenharmony_ci		{AUD_DCOC_PASS_IN, 0x00000000},
5548c2ecf20Sopenharmony_ci		{AUD_IIR1_2_SEL, 0x00000023},
5558c2ecf20Sopenharmony_ci		{AUD_IIR1_2_SHIFT, 0x00000000},
5568c2ecf20Sopenharmony_ci		{AUD_IIR1_3_SEL, 0x00000004},
5578c2ecf20Sopenharmony_ci		{AUD_IIR1_3_SHIFT, 0x00000007},
5588c2ecf20Sopenharmony_ci		{AUD_IIR1_4_SEL, 0x00000005},
5598c2ecf20Sopenharmony_ci		{AUD_IIR1_4_SHIFT, 0x00000007},
5608c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SEL, 0x00000007},
5618c2ecf20Sopenharmony_ci		{AUD_IIR3_0_SHIFT, 0x00000000},
5628c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_SRC_SEL, 0x00000011},
5638c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_SHIFT, 0x00000000},
5648c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_G0, 0x00007000},
5658c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_A0, 0x00000000},
5668c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_B0, 0x00000000},
5678c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_A1, 0x00000000},
5688c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_B1, 0x00000000},
5698c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_SRC_SEL, 0x00000011},
5708c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_SHIFT, 0x00000000},
5718c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_G0, 0x00007000},
5728c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A0, 0x00000000},
5738c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B0, 0x00000000},
5748c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A1, 0x00000000},
5758c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B1, 0x00000000},
5768c2ecf20Sopenharmony_ci		{AUD_OUT0_SEL, 0x0000003F},
5778c2ecf20Sopenharmony_ci		{AUD_OUT1_SEL, 0x0000003F},
5788c2ecf20Sopenharmony_ci		{AUD_DMD_RA_DDS, 0x00F5C285},
5798c2ecf20Sopenharmony_ci		{AUD_PLL_INT, 0x0000001E},
5808c2ecf20Sopenharmony_ci		{AUD_PLL_DDS, 0x00000000},
5818c2ecf20Sopenharmony_ci		{AUD_PLL_FRAC, 0x0000E542},
5828c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ1, 0x00000100},
5838c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ2, 0x00000200},
5848c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ3, 0x00000300},
5858c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ4, 0x00000400},
5868c2ecf20Sopenharmony_ci		{AUD_RATE_ADJ5, 0x00000500},
5878c2ecf20Sopenharmony_ci		{AUD_RATE_THRES_DMD, 0x000000C0},
5888c2ecf20Sopenharmony_ci		{ /* end of list */ },
5898c2ecf20Sopenharmony_ci	};
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	static const struct rlist a2_deemph50[] = {
5928c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_G0, 0x00000380},
5938c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_G0, 0x00000380},
5948c2ecf20Sopenharmony_ci		{AUD_DEEMPHGAIN_R, 0x000011e1},
5958c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER1_R, 0x0002a7bc},
5968c2ecf20Sopenharmony_ci		{AUD_DEEMPHNUMER2_R, 0x0003023c},
5978c2ecf20Sopenharmony_ci		{ /* end of list */ },
5988c2ecf20Sopenharmony_ci	};
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	set_audio_start(core, SEL_A2);
6018c2ecf20Sopenharmony_ci	switch (core->tvaudio) {
6028c2ecf20Sopenharmony_ci	case WW_BG:
6038c2ecf20Sopenharmony_ci		dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__);
6048c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_bgdk_common);
6058c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_bg);
6068c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_deemph50);
6078c2ecf20Sopenharmony_ci		break;
6088c2ecf20Sopenharmony_ci	case WW_DK:
6098c2ecf20Sopenharmony_ci		dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__);
6108c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_bgdk_common);
6118c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_dk);
6128c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_deemph50);
6138c2ecf20Sopenharmony_ci		break;
6148c2ecf20Sopenharmony_ci	case WW_I:
6158c2ecf20Sopenharmony_ci		dprintk("%s PAL-I A1 (status: known-good)\n", __func__);
6168c2ecf20Sopenharmony_ci		set_audio_registers(core, a1_i);
6178c2ecf20Sopenharmony_ci		set_audio_registers(core, a2_deemph50);
6188c2ecf20Sopenharmony_ci		break;
6198c2ecf20Sopenharmony_ci	case WW_L:
6208c2ecf20Sopenharmony_ci		dprintk("%s AM-L (status: devel)\n", __func__);
6218c2ecf20Sopenharmony_ci		set_audio_registers(core, am_l);
6228c2ecf20Sopenharmony_ci		break;
6238c2ecf20Sopenharmony_ci	case WW_NONE:
6248c2ecf20Sopenharmony_ci	case WW_BTSC:
6258c2ecf20Sopenharmony_ci	case WW_EIAJ:
6268c2ecf20Sopenharmony_ci	case WW_I2SPT:
6278c2ecf20Sopenharmony_ci	case WW_FM:
6288c2ecf20Sopenharmony_ci	case WW_I2SADC:
6298c2ecf20Sopenharmony_ci	case WW_M:
6308c2ecf20Sopenharmony_ci		dprintk("%s Warning: wrong value\n", __func__);
6318c2ecf20Sopenharmony_ci		return;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF;
6358c2ecf20Sopenharmony_ci	set_audio_finish(core, mode);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic void set_audio_standard_EIAJ(struct cx88_core *core)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	static const struct rlist eiaj[] = {
6418c2ecf20Sopenharmony_ci		/* TODO: eiaj register settings are not there yet ... */
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		{ /* end of list */ },
6448c2ecf20Sopenharmony_ci	};
6458c2ecf20Sopenharmony_ci	dprintk("%s (status: unknown)\n", __func__);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	set_audio_start(core, SEL_EIAJ);
6488c2ecf20Sopenharmony_ci	set_audio_registers(core, eiaj);
6498c2ecf20Sopenharmony_ci	set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic void set_audio_standard_FM(struct cx88_core *core,
6538c2ecf20Sopenharmony_ci				  enum cx88_deemph_type deemph)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	static const struct rlist fm_deemph_50[] = {
6568c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_G0, 0x0C45},
6578c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_A0, 0x6262},
6588c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_B0, 0x1C29},
6598c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_A1, 0x3FC66},
6608c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_B1, 0x399A},
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_G0, 0x0D80},
6638c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A0, 0x6262},
6648c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B0, 0x1C29},
6658c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A1, 0x3FC66},
6668c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B1, 0x399A},
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x0003},
6698c2ecf20Sopenharmony_ci		{ /* end of list */ },
6708c2ecf20Sopenharmony_ci	};
6718c2ecf20Sopenharmony_ci	static const struct rlist fm_deemph_75[] = {
6728c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_G0, 0x091B},
6738c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_A0, 0x6B68},
6748c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_B0, 0x11EC},
6758c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_A1, 0x3FC66},
6768c2ecf20Sopenharmony_ci		{AUD_DEEMPH0_B1, 0x399A},
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_G0, 0x0AA0},
6798c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A0, 0x6B68},
6808c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B0, 0x11EC},
6818c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_A1, 0x3FC66},
6828c2ecf20Sopenharmony_ci		{AUD_DEEMPH1_B1, 0x399A},
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x0003},
6858c2ecf20Sopenharmony_ci		{ /* end of list */ },
6868c2ecf20Sopenharmony_ci	};
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	/*
6898c2ecf20Sopenharmony_ci	 * It is enough to leave default values?
6908c2ecf20Sopenharmony_ci	 *
6918c2ecf20Sopenharmony_ci	 * No, it's not!  The deemphasis registers are reset to the 75us
6928c2ecf20Sopenharmony_ci	 * values by default.  Analyzing the spectrum of the decoded audio
6938c2ecf20Sopenharmony_ci	 * reveals that "no deemphasis" is the same as 75 us, while the 50 us
6948c2ecf20Sopenharmony_ci	 * setting results in less deemphasis.
6958c2ecf20Sopenharmony_ci	 */
6968c2ecf20Sopenharmony_ci	static const struct rlist fm_no_deemph[] = {
6978c2ecf20Sopenharmony_ci		{AUD_POLYPH80SCALEFAC, 0x0003},
6988c2ecf20Sopenharmony_ci		{ /* end of list */ },
6998c2ecf20Sopenharmony_ci	};
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	dprintk("%s (status: unknown)\n", __func__);
7028c2ecf20Sopenharmony_ci	set_audio_start(core, SEL_FMRADIO);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	switch (deemph) {
7058c2ecf20Sopenharmony_ci	default:
7068c2ecf20Sopenharmony_ci	case FM_NO_DEEMPH:
7078c2ecf20Sopenharmony_ci		set_audio_registers(core, fm_no_deemph);
7088c2ecf20Sopenharmony_ci		break;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	case FM_DEEMPH_50:
7118c2ecf20Sopenharmony_ci		set_audio_registers(core, fm_deemph_50);
7128c2ecf20Sopenharmony_ci		break;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	case FM_DEEMPH_75:
7158c2ecf20Sopenharmony_ci		set_audio_registers(core, fm_deemph_75);
7168c2ecf20Sopenharmony_ci		break;
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci/* ----------------------------------------------------------- */
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic int cx88_detect_nicam(struct cx88_core *core)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	int i, j = 0;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	dprintk("start nicam autodetect.\n");
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
7318c2ecf20Sopenharmony_ci		/* if bit1=1 then nicam is detected */
7328c2ecf20Sopenharmony_ci		j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci		if (j == 1) {
7358c2ecf20Sopenharmony_ci			dprintk("nicam is detected.\n");
7368c2ecf20Sopenharmony_ci			return 1;
7378c2ecf20Sopenharmony_ci		}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		/* wait a little bit for next reading status */
7408c2ecf20Sopenharmony_ci		usleep_range(10000, 20000);
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	dprintk("nicam is not detected.\n");
7448c2ecf20Sopenharmony_ci	return 0;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_civoid cx88_set_tvaudio(struct cx88_core *core)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	switch (core->tvaudio) {
7508c2ecf20Sopenharmony_ci	case WW_BTSC:
7518c2ecf20Sopenharmony_ci		set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
7528c2ecf20Sopenharmony_ci		break;
7538c2ecf20Sopenharmony_ci	case WW_BG:
7548c2ecf20Sopenharmony_ci	case WW_DK:
7558c2ecf20Sopenharmony_ci	case WW_M:
7568c2ecf20Sopenharmony_ci	case WW_I:
7578c2ecf20Sopenharmony_ci	case WW_L:
7588c2ecf20Sopenharmony_ci		/* prepare all dsp registers */
7598c2ecf20Sopenharmony_ci		set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		/*
7628c2ecf20Sopenharmony_ci		 * set nicam mode - otherwise
7638c2ecf20Sopenharmony_ci		 * AUD_NICAM_STATUS2 contains wrong values
7648c2ecf20Sopenharmony_ci		 */
7658c2ecf20Sopenharmony_ci		set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
7668c2ecf20Sopenharmony_ci		if (cx88_detect_nicam(core) == 0) {
7678c2ecf20Sopenharmony_ci			/* fall back to fm / am mono */
7688c2ecf20Sopenharmony_ci			set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
7698c2ecf20Sopenharmony_ci			core->audiomode_current = V4L2_TUNER_MODE_MONO;
7708c2ecf20Sopenharmony_ci			core->use_nicam = 0;
7718c2ecf20Sopenharmony_ci		} else {
7728c2ecf20Sopenharmony_ci			core->use_nicam = 1;
7738c2ecf20Sopenharmony_ci		}
7748c2ecf20Sopenharmony_ci		break;
7758c2ecf20Sopenharmony_ci	case WW_EIAJ:
7768c2ecf20Sopenharmony_ci		set_audio_standard_EIAJ(core);
7778c2ecf20Sopenharmony_ci		break;
7788c2ecf20Sopenharmony_ci	case WW_FM:
7798c2ecf20Sopenharmony_ci		set_audio_standard_FM(core, radio_deemphasis);
7808c2ecf20Sopenharmony_ci		break;
7818c2ecf20Sopenharmony_ci	case WW_I2SADC:
7828c2ecf20Sopenharmony_ci		set_audio_start(core, 0x01);
7838c2ecf20Sopenharmony_ci		/*
7848c2ecf20Sopenharmony_ci		 * Slave/Philips/Autobaud
7858c2ecf20Sopenharmony_ci		 * NB on Nova-S bit1 NPhilipsSony appears to be inverted:
7868c2ecf20Sopenharmony_ci		 *	0= Sony, 1=Philips
7878c2ecf20Sopenharmony_ci		 */
7888c2ecf20Sopenharmony_ci		cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl);
7898c2ecf20Sopenharmony_ci		/* Switch to "I2S ADC mode" */
7908c2ecf20Sopenharmony_ci		cx_write(AUD_I2SCNTL, 0x1);
7918c2ecf20Sopenharmony_ci		set_audio_finish(core, EN_I2SIN_ENABLE);
7928c2ecf20Sopenharmony_ci		break;
7938c2ecf20Sopenharmony_ci	case WW_NONE:
7948c2ecf20Sopenharmony_ci	case WW_I2SPT:
7958c2ecf20Sopenharmony_ci		pr_info("unknown tv audio mode [%d]\n", core->tvaudio);
7968c2ecf20Sopenharmony_ci		break;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx88_set_tvaudio);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_civoid cx88_newstation(struct cx88_core *core)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	core->audiomode_manual = UNSET;
8048c2ecf20Sopenharmony_ci	core->last_change = jiffies;
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx88_newstation);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_civoid cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	static const char * const m[] = { "stereo", "dual mono",
8118c2ecf20Sopenharmony_ci					  "mono",   "sap" };
8128c2ecf20Sopenharmony_ci	static const char * const p[] = { "no pilot", "pilot c1",
8138c2ecf20Sopenharmony_ci					  "pilot c2", "?" };
8148c2ecf20Sopenharmony_ci	u32 reg, mode, pilot;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	reg = cx_read(AUD_STATUS);
8178c2ecf20Sopenharmony_ci	mode = reg & 0x03;
8188c2ecf20Sopenharmony_ci	pilot = (reg >> 2) & 0x03;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	if (core->astat != reg)
8218c2ecf20Sopenharmony_ci		dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
8228c2ecf20Sopenharmony_ci			reg, m[mode], p[pilot],
8238c2ecf20Sopenharmony_ci			aud_ctl_names[cx_read(AUD_CTL) & 63]);
8248c2ecf20Sopenharmony_ci	core->astat = reg;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
8278c2ecf20Sopenharmony_ci	    V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
8288c2ecf20Sopenharmony_ci	t->rxsubchans = UNSET;
8298c2ecf20Sopenharmony_ci	t->audmode = V4L2_TUNER_MODE_MONO;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	switch (mode) {
8328c2ecf20Sopenharmony_ci	case 0:
8338c2ecf20Sopenharmony_ci		t->audmode = V4L2_TUNER_MODE_STEREO;
8348c2ecf20Sopenharmony_ci		break;
8358c2ecf20Sopenharmony_ci	case 1:
8368c2ecf20Sopenharmony_ci		t->audmode = V4L2_TUNER_MODE_LANG2;
8378c2ecf20Sopenharmony_ci		break;
8388c2ecf20Sopenharmony_ci	case 2:
8398c2ecf20Sopenharmony_ci		t->audmode = V4L2_TUNER_MODE_MONO;
8408c2ecf20Sopenharmony_ci		break;
8418c2ecf20Sopenharmony_ci	case 3:
8428c2ecf20Sopenharmony_ci		t->audmode = V4L2_TUNER_MODE_SAP;
8438c2ecf20Sopenharmony_ci		break;
8448c2ecf20Sopenharmony_ci	}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	switch (core->tvaudio) {
8478c2ecf20Sopenharmony_ci	case WW_BTSC:
8488c2ecf20Sopenharmony_ci	case WW_BG:
8498c2ecf20Sopenharmony_ci	case WW_DK:
8508c2ecf20Sopenharmony_ci	case WW_M:
8518c2ecf20Sopenharmony_ci	case WW_EIAJ:
8528c2ecf20Sopenharmony_ci		if (!core->use_nicam) {
8538c2ecf20Sopenharmony_ci			t->rxsubchans = cx88_dsp_detect_stereo_sap(core);
8548c2ecf20Sopenharmony_ci			break;
8558c2ecf20Sopenharmony_ci		}
8568c2ecf20Sopenharmony_ci		break;
8578c2ecf20Sopenharmony_ci	case WW_NONE:
8588c2ecf20Sopenharmony_ci	case WW_I:
8598c2ecf20Sopenharmony_ci	case WW_L:
8608c2ecf20Sopenharmony_ci	case WW_I2SPT:
8618c2ecf20Sopenharmony_ci	case WW_FM:
8628c2ecf20Sopenharmony_ci	case WW_I2SADC:
8638c2ecf20Sopenharmony_ci		/* nothing */
8648c2ecf20Sopenharmony_ci		break;
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/* If software stereo detection is not supported... */
8688c2ecf20Sopenharmony_ci	if (t->rxsubchans == UNSET) {
8698c2ecf20Sopenharmony_ci		t->rxsubchans = V4L2_TUNER_SUB_MONO;
8708c2ecf20Sopenharmony_ci		/*
8718c2ecf20Sopenharmony_ci		 * If the hardware itself detected stereo, also return
8728c2ecf20Sopenharmony_ci		 * stereo as an available subchannel
8738c2ecf20Sopenharmony_ci		 */
8748c2ecf20Sopenharmony_ci		if (t->audmode == V4L2_TUNER_MODE_STEREO)
8758c2ecf20Sopenharmony_ci			t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci}
8788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx88_get_stereo);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_civoid cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
8828c2ecf20Sopenharmony_ci{
8838c2ecf20Sopenharmony_ci	u32 ctl = UNSET;
8848c2ecf20Sopenharmony_ci	u32 mask = UNSET;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	if (manual) {
8878c2ecf20Sopenharmony_ci		core->audiomode_manual = mode;
8888c2ecf20Sopenharmony_ci	} else {
8898c2ecf20Sopenharmony_ci		if (core->audiomode_manual != UNSET)
8908c2ecf20Sopenharmony_ci			return;
8918c2ecf20Sopenharmony_ci	}
8928c2ecf20Sopenharmony_ci	core->audiomode_current = mode;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	switch (core->tvaudio) {
8958c2ecf20Sopenharmony_ci	case WW_BTSC:
8968c2ecf20Sopenharmony_ci		switch (mode) {
8978c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_MONO:
8988c2ecf20Sopenharmony_ci			set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO);
8998c2ecf20Sopenharmony_ci			break;
9008c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_LANG1:
9018c2ecf20Sopenharmony_ci			set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
9028c2ecf20Sopenharmony_ci			break;
9038c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_LANG2:
9048c2ecf20Sopenharmony_ci			set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP);
9058c2ecf20Sopenharmony_ci			break;
9068c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_STEREO:
9078c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_LANG1_LANG2:
9088c2ecf20Sopenharmony_ci			set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO);
9098c2ecf20Sopenharmony_ci			break;
9108c2ecf20Sopenharmony_ci		}
9118c2ecf20Sopenharmony_ci		break;
9128c2ecf20Sopenharmony_ci	case WW_BG:
9138c2ecf20Sopenharmony_ci	case WW_DK:
9148c2ecf20Sopenharmony_ci	case WW_M:
9158c2ecf20Sopenharmony_ci	case WW_I:
9168c2ecf20Sopenharmony_ci	case WW_L:
9178c2ecf20Sopenharmony_ci		if (core->use_nicam == 1) {
9188c2ecf20Sopenharmony_ci			switch (mode) {
9198c2ecf20Sopenharmony_ci			case V4L2_TUNER_MODE_MONO:
9208c2ecf20Sopenharmony_ci			case V4L2_TUNER_MODE_LANG1:
9218c2ecf20Sopenharmony_ci				set_audio_standard_NICAM(core,
9228c2ecf20Sopenharmony_ci							 EN_NICAM_FORCE_MONO1);
9238c2ecf20Sopenharmony_ci				break;
9248c2ecf20Sopenharmony_ci			case V4L2_TUNER_MODE_LANG2:
9258c2ecf20Sopenharmony_ci				set_audio_standard_NICAM(core,
9268c2ecf20Sopenharmony_ci							 EN_NICAM_FORCE_MONO2);
9278c2ecf20Sopenharmony_ci				break;
9288c2ecf20Sopenharmony_ci			case V4L2_TUNER_MODE_STEREO:
9298c2ecf20Sopenharmony_ci			case V4L2_TUNER_MODE_LANG1_LANG2:
9308c2ecf20Sopenharmony_ci				set_audio_standard_NICAM(core,
9318c2ecf20Sopenharmony_ci							 EN_NICAM_FORCE_STEREO);
9328c2ecf20Sopenharmony_ci				break;
9338c2ecf20Sopenharmony_ci			}
9348c2ecf20Sopenharmony_ci		} else {
9358c2ecf20Sopenharmony_ci			if ((core->tvaudio == WW_I) ||
9368c2ecf20Sopenharmony_ci			    (core->tvaudio == WW_L)) {
9378c2ecf20Sopenharmony_ci				/* fall back to fm / am mono */
9388c2ecf20Sopenharmony_ci				set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
9398c2ecf20Sopenharmony_ci			} else {
9408c2ecf20Sopenharmony_ci				/* TODO: Add A2 autodection */
9418c2ecf20Sopenharmony_ci				mask = 0x3f;
9428c2ecf20Sopenharmony_ci				switch (mode) {
9438c2ecf20Sopenharmony_ci				case V4L2_TUNER_MODE_MONO:
9448c2ecf20Sopenharmony_ci				case V4L2_TUNER_MODE_LANG1:
9458c2ecf20Sopenharmony_ci					ctl = EN_A2_FORCE_MONO1;
9468c2ecf20Sopenharmony_ci					break;
9478c2ecf20Sopenharmony_ci				case V4L2_TUNER_MODE_LANG2:
9488c2ecf20Sopenharmony_ci					ctl = EN_A2_FORCE_MONO2;
9498c2ecf20Sopenharmony_ci					break;
9508c2ecf20Sopenharmony_ci				case V4L2_TUNER_MODE_STEREO:
9518c2ecf20Sopenharmony_ci				case V4L2_TUNER_MODE_LANG1_LANG2:
9528c2ecf20Sopenharmony_ci					ctl = EN_A2_FORCE_STEREO;
9538c2ecf20Sopenharmony_ci					break;
9548c2ecf20Sopenharmony_ci				}
9558c2ecf20Sopenharmony_ci			}
9568c2ecf20Sopenharmony_ci		}
9578c2ecf20Sopenharmony_ci		break;
9588c2ecf20Sopenharmony_ci	case WW_FM:
9598c2ecf20Sopenharmony_ci		switch (mode) {
9608c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_MONO:
9618c2ecf20Sopenharmony_ci			ctl = EN_FMRADIO_FORCE_MONO;
9628c2ecf20Sopenharmony_ci			mask = 0x3f;
9638c2ecf20Sopenharmony_ci			break;
9648c2ecf20Sopenharmony_ci		case V4L2_TUNER_MODE_STEREO:
9658c2ecf20Sopenharmony_ci			ctl = EN_FMRADIO_AUTO_STEREO;
9668c2ecf20Sopenharmony_ci			mask = 0x3f;
9678c2ecf20Sopenharmony_ci			break;
9688c2ecf20Sopenharmony_ci		}
9698c2ecf20Sopenharmony_ci		break;
9708c2ecf20Sopenharmony_ci	case WW_I2SADC:
9718c2ecf20Sopenharmony_ci	case WW_NONE:
9728c2ecf20Sopenharmony_ci	case WW_EIAJ:
9738c2ecf20Sopenharmony_ci	case WW_I2SPT:
9748c2ecf20Sopenharmony_ci		/* DO NOTHING */
9758c2ecf20Sopenharmony_ci		break;
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (ctl != UNSET) {
9798c2ecf20Sopenharmony_ci		dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x [status=0x%x,ctl=0x%x,vol=0x%x]\n",
9808c2ecf20Sopenharmony_ci			mask, ctl, cx_read(AUD_STATUS),
9818c2ecf20Sopenharmony_ci			cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
9828c2ecf20Sopenharmony_ci		cx_andor(AUD_CTL, mask, ctl);
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx88_set_stereo);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ciint cx88_audio_thread(void *data)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct cx88_core *core = data;
9908c2ecf20Sopenharmony_ci	struct v4l2_tuner t;
9918c2ecf20Sopenharmony_ci	u32 mode = 0;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	dprintk("cx88: tvaudio thread started\n");
9948c2ecf20Sopenharmony_ci	set_freezable();
9958c2ecf20Sopenharmony_ci	for (;;) {
9968c2ecf20Sopenharmony_ci		msleep_interruptible(1000);
9978c2ecf20Sopenharmony_ci		if (kthread_should_stop())
9988c2ecf20Sopenharmony_ci			break;
9998c2ecf20Sopenharmony_ci		try_to_freeze();
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci		switch (core->tvaudio) {
10028c2ecf20Sopenharmony_ci		case WW_BG:
10038c2ecf20Sopenharmony_ci		case WW_DK:
10048c2ecf20Sopenharmony_ci		case WW_M:
10058c2ecf20Sopenharmony_ci		case WW_I:
10068c2ecf20Sopenharmony_ci		case WW_L:
10078c2ecf20Sopenharmony_ci			if (core->use_nicam)
10088c2ecf20Sopenharmony_ci				goto hw_autodetect;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci			/* just monitor the audio status for now ... */
10118c2ecf20Sopenharmony_ci			memset(&t, 0, sizeof(t));
10128c2ecf20Sopenharmony_ci			cx88_get_stereo(core, &t);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci			if (core->audiomode_manual != UNSET)
10158c2ecf20Sopenharmony_ci				/* manually set, don't do anything. */
10168c2ecf20Sopenharmony_ci				continue;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci			/* monitor signal and set stereo if available */
10198c2ecf20Sopenharmony_ci			if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
10208c2ecf20Sopenharmony_ci				mode = V4L2_TUNER_MODE_STEREO;
10218c2ecf20Sopenharmony_ci			else
10228c2ecf20Sopenharmony_ci				mode = V4L2_TUNER_MODE_MONO;
10238c2ecf20Sopenharmony_ci			if (mode == core->audiomode_current)
10248c2ecf20Sopenharmony_ci				continue;
10258c2ecf20Sopenharmony_ci			/* automatically switch to best available mode */
10268c2ecf20Sopenharmony_ci			cx88_set_stereo(core, mode, 0);
10278c2ecf20Sopenharmony_ci			break;
10288c2ecf20Sopenharmony_ci		case WW_NONE:
10298c2ecf20Sopenharmony_ci		case WW_BTSC:
10308c2ecf20Sopenharmony_ci		case WW_EIAJ:
10318c2ecf20Sopenharmony_ci		case WW_I2SPT:
10328c2ecf20Sopenharmony_ci		case WW_FM:
10338c2ecf20Sopenharmony_ci		case WW_I2SADC:
10348c2ecf20Sopenharmony_cihw_autodetect:
10358c2ecf20Sopenharmony_ci			/*
10368c2ecf20Sopenharmony_ci			 * stereo autodetection is supported by hardware so
10378c2ecf20Sopenharmony_ci			 * we don't need to do it manually. Do nothing.
10388c2ecf20Sopenharmony_ci			 */
10398c2ecf20Sopenharmony_ci			break;
10408c2ecf20Sopenharmony_ci		}
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	dprintk("cx88: tvaudio thread exiting\n");
10448c2ecf20Sopenharmony_ci	return 0;
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cx88_audio_thread);
1047