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