brintos

brintos / linux-shallow public Read only

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