xref: /openbmc/linux/drivers/media/tuners/tda9887.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*09c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ccae7af2SMauro Carvalho Chehab #include <linux/module.h>
3ccae7af2SMauro Carvalho Chehab #include <linux/kernel.h>
4ccae7af2SMauro Carvalho Chehab #include <linux/i2c.h>
5ccae7af2SMauro Carvalho Chehab #include <linux/types.h>
6ccae7af2SMauro Carvalho Chehab #include <linux/init.h>
7ccae7af2SMauro Carvalho Chehab #include <linux/errno.h>
8ccae7af2SMauro Carvalho Chehab #include <linux/delay.h>
9ccae7af2SMauro Carvalho Chehab #include <linux/videodev2.h>
10ccae7af2SMauro Carvalho Chehab #include <media/v4l2-common.h>
11ccae7af2SMauro Carvalho Chehab #include <media/tuner.h>
12ccae7af2SMauro Carvalho Chehab #include "tuner-i2c.h"
13ccae7af2SMauro Carvalho Chehab #include "tda9887.h"
14ccae7af2SMauro Carvalho Chehab 
15ccae7af2SMauro Carvalho Chehab 
16ccae7af2SMauro Carvalho Chehab /* Chips:
17ccae7af2SMauro Carvalho Chehab    TDA9885 (PAL, NTSC)
18ccae7af2SMauro Carvalho Chehab    TDA9886 (PAL, SECAM, NTSC)
19ccae7af2SMauro Carvalho Chehab    TDA9887 (PAL, SECAM, NTSC, FM Radio)
20ccae7af2SMauro Carvalho Chehab 
21ccae7af2SMauro Carvalho Chehab    Used as part of several tuners
22ccae7af2SMauro Carvalho Chehab */
23ccae7af2SMauro Carvalho Chehab 
24ccae7af2SMauro Carvalho Chehab static int debug;
25ccae7af2SMauro Carvalho Chehab module_param(debug, int, 0644);
26ccae7af2SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "enable verbose debug messages");
27ccae7af2SMauro Carvalho Chehab 
28ccae7af2SMauro Carvalho Chehab static DEFINE_MUTEX(tda9887_list_mutex);
29ccae7af2SMauro Carvalho Chehab static LIST_HEAD(hybrid_tuner_instance_list);
30ccae7af2SMauro Carvalho Chehab 
31ccae7af2SMauro Carvalho Chehab struct tda9887_priv {
32ccae7af2SMauro Carvalho Chehab 	struct tuner_i2c_props i2c_props;
33ccae7af2SMauro Carvalho Chehab 	struct list_head hybrid_tuner_instance_list;
34ccae7af2SMauro Carvalho Chehab 
35ccae7af2SMauro Carvalho Chehab 	unsigned char	   data[4];
36ccae7af2SMauro Carvalho Chehab 	unsigned int       config;
37ccae7af2SMauro Carvalho Chehab 	unsigned int       mode;
38ccae7af2SMauro Carvalho Chehab 	unsigned int       audmode;
39ccae7af2SMauro Carvalho Chehab 	v4l2_std_id        std;
40ccae7af2SMauro Carvalho Chehab 
41ccae7af2SMauro Carvalho Chehab 	bool               standby;
42ccae7af2SMauro Carvalho Chehab };
43ccae7af2SMauro Carvalho Chehab 
44ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
45ccae7af2SMauro Carvalho Chehab 
46ccae7af2SMauro Carvalho Chehab #define UNSET       (-1U)
47ccae7af2SMauro Carvalho Chehab 
48ccae7af2SMauro Carvalho Chehab struct tvnorm {
49ccae7af2SMauro Carvalho Chehab 	v4l2_std_id       std;
50ccae7af2SMauro Carvalho Chehab 	char              *name;
51ccae7af2SMauro Carvalho Chehab 	unsigned char     b;
52ccae7af2SMauro Carvalho Chehab 	unsigned char     c;
53ccae7af2SMauro Carvalho Chehab 	unsigned char     e;
54ccae7af2SMauro Carvalho Chehab };
55ccae7af2SMauro Carvalho Chehab 
56ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
57ccae7af2SMauro Carvalho Chehab 
58ccae7af2SMauro Carvalho Chehab //
59ccae7af2SMauro Carvalho Chehab // TDA defines
60ccae7af2SMauro Carvalho Chehab //
61ccae7af2SMauro Carvalho Chehab 
62ccae7af2SMauro Carvalho Chehab //// first reg (b)
63ccae7af2SMauro Carvalho Chehab #define cVideoTrapBypassOFF     0x00    // bit b0
64ccae7af2SMauro Carvalho Chehab #define cVideoTrapBypassON      0x01    // bit b0
65ccae7af2SMauro Carvalho Chehab 
66ccae7af2SMauro Carvalho Chehab #define cAutoMuteFmInactive     0x00    // bit b1
67ccae7af2SMauro Carvalho Chehab #define cAutoMuteFmActive       0x02    // bit b1
68ccae7af2SMauro Carvalho Chehab 
69ccae7af2SMauro Carvalho Chehab #define cIntercarrier           0x00    // bit b2
70ccae7af2SMauro Carvalho Chehab #define cQSS                    0x04    // bit b2
71ccae7af2SMauro Carvalho Chehab 
72ccae7af2SMauro Carvalho Chehab #define cPositiveAmTV           0x00    // bit b3:4
73ccae7af2SMauro Carvalho Chehab #define cFmRadio                0x08    // bit b3:4
74ccae7af2SMauro Carvalho Chehab #define cNegativeFmTV           0x10    // bit b3:4
75ccae7af2SMauro Carvalho Chehab 
76ccae7af2SMauro Carvalho Chehab 
77ccae7af2SMauro Carvalho Chehab #define cForcedMuteAudioON      0x20    // bit b5
78ccae7af2SMauro Carvalho Chehab #define cForcedMuteAudioOFF     0x00    // bit b5
79ccae7af2SMauro Carvalho Chehab 
80ccae7af2SMauro Carvalho Chehab #define cOutputPort1Active      0x00    // bit b6
81ccae7af2SMauro Carvalho Chehab #define cOutputPort1Inactive    0x40    // bit b6
82ccae7af2SMauro Carvalho Chehab 
83ccae7af2SMauro Carvalho Chehab #define cOutputPort2Active      0x00    // bit b7
84ccae7af2SMauro Carvalho Chehab #define cOutputPort2Inactive    0x80    // bit b7
85ccae7af2SMauro Carvalho Chehab 
86ccae7af2SMauro Carvalho Chehab 
87ccae7af2SMauro Carvalho Chehab //// second reg (c)
88ccae7af2SMauro Carvalho Chehab #define cDeemphasisOFF          0x00    // bit c5
89ccae7af2SMauro Carvalho Chehab #define cDeemphasisON           0x20    // bit c5
90ccae7af2SMauro Carvalho Chehab 
91ccae7af2SMauro Carvalho Chehab #define cDeemphasis75           0x00    // bit c6
92ccae7af2SMauro Carvalho Chehab #define cDeemphasis50           0x40    // bit c6
93ccae7af2SMauro Carvalho Chehab 
94ccae7af2SMauro Carvalho Chehab #define cAudioGain0             0x00    // bit c7
95ccae7af2SMauro Carvalho Chehab #define cAudioGain6             0x80    // bit c7
96ccae7af2SMauro Carvalho Chehab 
97ccae7af2SMauro Carvalho Chehab #define cTopMask                0x1f    // bit c0:4
98ccae7af2SMauro Carvalho Chehab #define cTopDefault		0x10	// bit c0:4
99ccae7af2SMauro Carvalho Chehab 
100ccae7af2SMauro Carvalho Chehab //// third reg (e)
101ccae7af2SMauro Carvalho Chehab #define cAudioIF_4_5             0x00    // bit e0:1
102ccae7af2SMauro Carvalho Chehab #define cAudioIF_5_5             0x01    // bit e0:1
103ccae7af2SMauro Carvalho Chehab #define cAudioIF_6_0             0x02    // bit e0:1
104ccae7af2SMauro Carvalho Chehab #define cAudioIF_6_5             0x03    // bit e0:1
105ccae7af2SMauro Carvalho Chehab 
106ccae7af2SMauro Carvalho Chehab 
107ccae7af2SMauro Carvalho Chehab #define cVideoIFMask		0x1c	// bit e2:4
108ccae7af2SMauro Carvalho Chehab /* Video IF selection in TV Mode (bit B3=0) */
109ccae7af2SMauro Carvalho Chehab #define cVideoIF_58_75           0x00    // bit e2:4
110ccae7af2SMauro Carvalho Chehab #define cVideoIF_45_75           0x04    // bit e2:4
111ccae7af2SMauro Carvalho Chehab #define cVideoIF_38_90           0x08    // bit e2:4
112ccae7af2SMauro Carvalho Chehab #define cVideoIF_38_00           0x0C    // bit e2:4
113ccae7af2SMauro Carvalho Chehab #define cVideoIF_33_90           0x10    // bit e2:4
114ccae7af2SMauro Carvalho Chehab #define cVideoIF_33_40           0x14    // bit e2:4
115ccae7af2SMauro Carvalho Chehab #define cRadioIF_45_75           0x18    // bit e2:4
116ccae7af2SMauro Carvalho Chehab #define cRadioIF_38_90           0x1C    // bit e2:4
117ccae7af2SMauro Carvalho Chehab 
118ccae7af2SMauro Carvalho Chehab /* IF1 selection in Radio Mode (bit B3=1) */
119ccae7af2SMauro Carvalho Chehab #define cRadioIF_33_30		0x00	// bit e2,4 (also 0x10,0x14)
120ccae7af2SMauro Carvalho Chehab #define cRadioIF_41_30		0x04	// bit e2,4
121ccae7af2SMauro Carvalho Chehab 
122ccae7af2SMauro Carvalho Chehab /* Output of AFC pin in radio mode when bit E7=1 */
123ccae7af2SMauro Carvalho Chehab #define cRadioAGC_SIF		0x00	// bit e3
124ccae7af2SMauro Carvalho Chehab #define cRadioAGC_FM		0x08	// bit e3
125ccae7af2SMauro Carvalho Chehab 
126ccae7af2SMauro Carvalho Chehab #define cTunerGainNormal         0x00    // bit e5
127ccae7af2SMauro Carvalho Chehab #define cTunerGainLow            0x20    // bit e5
128ccae7af2SMauro Carvalho Chehab 
129ccae7af2SMauro Carvalho Chehab #define cGating_18               0x00    // bit e6
130ccae7af2SMauro Carvalho Chehab #define cGating_36               0x40    // bit e6
131ccae7af2SMauro Carvalho Chehab 
132ccae7af2SMauro Carvalho Chehab #define cAgcOutON                0x80    // bit e7
133ccae7af2SMauro Carvalho Chehab #define cAgcOutOFF               0x00    // bit e7
134ccae7af2SMauro Carvalho Chehab 
135ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
136ccae7af2SMauro Carvalho Chehab 
137ccae7af2SMauro Carvalho Chehab static struct tvnorm tvnorms[] = {
138ccae7af2SMauro Carvalho Chehab 	{
139ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
140ccae7af2SMauro Carvalho Chehab 		.name  = "PAL-BGHN",
141ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
142ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
143ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
144ccae7af2SMauro Carvalho Chehab 			   cDeemphasis50  |
145ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
146ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
147ccae7af2SMauro Carvalho Chehab 			   cAudioIF_5_5   |
148ccae7af2SMauro Carvalho Chehab 			   cVideoIF_38_90 ),
149ccae7af2SMauro Carvalho Chehab 	},{
150ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_PAL_I,
151ccae7af2SMauro Carvalho Chehab 		.name  = "PAL-I",
152ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
153ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
154ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
155ccae7af2SMauro Carvalho Chehab 			   cDeemphasis50  |
156ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
157ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
158ccae7af2SMauro Carvalho Chehab 			   cAudioIF_6_0   |
159ccae7af2SMauro Carvalho Chehab 			   cVideoIF_38_90 ),
160ccae7af2SMauro Carvalho Chehab 	},{
161ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_PAL_DK,
162ccae7af2SMauro Carvalho Chehab 		.name  = "PAL-DK",
163ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
164ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
165ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
166ccae7af2SMauro Carvalho Chehab 			   cDeemphasis50  |
167ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
168ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
169ccae7af2SMauro Carvalho Chehab 			   cAudioIF_6_5   |
170ccae7af2SMauro Carvalho Chehab 			   cVideoIF_38_90 ),
171ccae7af2SMauro Carvalho Chehab 	},{
172ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
173ccae7af2SMauro Carvalho Chehab 		.name  = "PAL-M/Nc",
174ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
175ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
176ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
177ccae7af2SMauro Carvalho Chehab 			   cDeemphasis75  |
178ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
179ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
180ccae7af2SMauro Carvalho Chehab 			   cAudioIF_4_5   |
181ccae7af2SMauro Carvalho Chehab 			   cVideoIF_45_75 ),
182ccae7af2SMauro Carvalho Chehab 	},{
183ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
184ccae7af2SMauro Carvalho Chehab 		.name  = "SECAM-BGH",
185ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
186ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
187ccae7af2SMauro Carvalho Chehab 		.c     = ( cTopDefault),
188ccae7af2SMauro Carvalho Chehab 		.e     = ( cAudioIF_5_5   |
189ccae7af2SMauro Carvalho Chehab 			   cVideoIF_38_90 ),
190ccae7af2SMauro Carvalho Chehab 	},{
191ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_SECAM_L,
192ccae7af2SMauro Carvalho Chehab 		.name  = "SECAM-L",
193ccae7af2SMauro Carvalho Chehab 		.b     = ( cPositiveAmTV  |
194ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
195ccae7af2SMauro Carvalho Chehab 		.c     = ( cTopDefault),
196ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36	  |
197ccae7af2SMauro Carvalho Chehab 			   cAudioIF_6_5   |
198ccae7af2SMauro Carvalho Chehab 			   cVideoIF_38_90 ),
199ccae7af2SMauro Carvalho Chehab 	},{
200ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_SECAM_LC,
201ccae7af2SMauro Carvalho Chehab 		.name  = "SECAM-L'",
202ccae7af2SMauro Carvalho Chehab 		.b     = ( cOutputPort2Inactive |
203ccae7af2SMauro Carvalho Chehab 			   cPositiveAmTV  |
204ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
205ccae7af2SMauro Carvalho Chehab 		.c     = ( cTopDefault),
206ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36	  |
207ccae7af2SMauro Carvalho Chehab 			   cAudioIF_6_5   |
208ccae7af2SMauro Carvalho Chehab 			   cVideoIF_33_90 ),
209ccae7af2SMauro Carvalho Chehab 	},{
210ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_SECAM_DK,
211ccae7af2SMauro Carvalho Chehab 		.name  = "SECAM-DK",
212ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
213ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
214ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
215ccae7af2SMauro Carvalho Chehab 			   cDeemphasis50  |
216ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
217ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
218ccae7af2SMauro Carvalho Chehab 			   cAudioIF_6_5   |
219ccae7af2SMauro Carvalho Chehab 			   cVideoIF_38_90 ),
220ccae7af2SMauro Carvalho Chehab 	},{
221ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
222ccae7af2SMauro Carvalho Chehab 		.name  = "NTSC-M",
223ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
224ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
225ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
226ccae7af2SMauro Carvalho Chehab 			   cDeemphasis75  |
227ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
228ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
229ccae7af2SMauro Carvalho Chehab 			   cAudioIF_4_5   |
230ccae7af2SMauro Carvalho Chehab 			   cVideoIF_45_75 ),
231ccae7af2SMauro Carvalho Chehab 	},{
232ccae7af2SMauro Carvalho Chehab 		.std   = V4L2_STD_NTSC_M_JP,
233ccae7af2SMauro Carvalho Chehab 		.name  = "NTSC-M-JP",
234ccae7af2SMauro Carvalho Chehab 		.b     = ( cNegativeFmTV  |
235ccae7af2SMauro Carvalho Chehab 			   cQSS           ),
236ccae7af2SMauro Carvalho Chehab 		.c     = ( cDeemphasisON  |
237ccae7af2SMauro Carvalho Chehab 			   cDeemphasis50  |
238ccae7af2SMauro Carvalho Chehab 			   cTopDefault),
239ccae7af2SMauro Carvalho Chehab 		.e     = ( cGating_36     |
240ccae7af2SMauro Carvalho Chehab 			   cAudioIF_4_5   |
241ccae7af2SMauro Carvalho Chehab 			   cVideoIF_58_75 ),
242ccae7af2SMauro Carvalho Chehab 	}
243ccae7af2SMauro Carvalho Chehab };
244ccae7af2SMauro Carvalho Chehab 
245ccae7af2SMauro Carvalho Chehab static struct tvnorm radio_stereo = {
246ccae7af2SMauro Carvalho Chehab 	.name = "Radio Stereo",
247ccae7af2SMauro Carvalho Chehab 	.b    = ( cFmRadio       |
248ccae7af2SMauro Carvalho Chehab 		  cQSS           ),
249ccae7af2SMauro Carvalho Chehab 	.c    = ( cDeemphasisOFF |
250ccae7af2SMauro Carvalho Chehab 		  cAudioGain6    |
251ccae7af2SMauro Carvalho Chehab 		  cTopDefault),
252ccae7af2SMauro Carvalho Chehab 	.e    = ( cTunerGainLow  |
253ccae7af2SMauro Carvalho Chehab 		  cAudioIF_5_5   |
254ccae7af2SMauro Carvalho Chehab 		  cRadioIF_38_90 ),
255ccae7af2SMauro Carvalho Chehab };
256ccae7af2SMauro Carvalho Chehab 
257ccae7af2SMauro Carvalho Chehab static struct tvnorm radio_mono = {
258ccae7af2SMauro Carvalho Chehab 	.name = "Radio Mono",
259ccae7af2SMauro Carvalho Chehab 	.b    = ( cFmRadio       |
260ccae7af2SMauro Carvalho Chehab 		  cQSS           ),
261ccae7af2SMauro Carvalho Chehab 	.c    = ( cDeemphasisON  |
262ccae7af2SMauro Carvalho Chehab 		  cDeemphasis75  |
263ccae7af2SMauro Carvalho Chehab 		  cTopDefault),
264ccae7af2SMauro Carvalho Chehab 	.e    = ( cTunerGainLow  |
265ccae7af2SMauro Carvalho Chehab 		  cAudioIF_5_5   |
266ccae7af2SMauro Carvalho Chehab 		  cRadioIF_38_90 ),
267ccae7af2SMauro Carvalho Chehab };
268ccae7af2SMauro Carvalho Chehab 
269ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
270ccae7af2SMauro Carvalho Chehab 
dump_read_message(struct dvb_frontend * fe,unsigned char * buf)271ccae7af2SMauro Carvalho Chehab static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
272ccae7af2SMauro Carvalho Chehab {
273ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
274ccae7af2SMauro Carvalho Chehab 
275ccae7af2SMauro Carvalho Chehab 	static char *afc[16] = {
276ccae7af2SMauro Carvalho Chehab 		"- 12.5 kHz",
277ccae7af2SMauro Carvalho Chehab 		"- 37.5 kHz",
278ccae7af2SMauro Carvalho Chehab 		"- 62.5 kHz",
279ccae7af2SMauro Carvalho Chehab 		"- 87.5 kHz",
280ccae7af2SMauro Carvalho Chehab 		"-112.5 kHz",
281ccae7af2SMauro Carvalho Chehab 		"-137.5 kHz",
282ccae7af2SMauro Carvalho Chehab 		"-162.5 kHz",
283ccae7af2SMauro Carvalho Chehab 		"-187.5 kHz [min]",
284ccae7af2SMauro Carvalho Chehab 		"+187.5 kHz [max]",
285ccae7af2SMauro Carvalho Chehab 		"+162.5 kHz",
286ccae7af2SMauro Carvalho Chehab 		"+137.5 kHz",
287ccae7af2SMauro Carvalho Chehab 		"+112.5 kHz",
288ccae7af2SMauro Carvalho Chehab 		"+ 87.5 kHz",
289ccae7af2SMauro Carvalho Chehab 		"+ 62.5 kHz",
290ccae7af2SMauro Carvalho Chehab 		"+ 37.5 kHz",
291ccae7af2SMauro Carvalho Chehab 		"+ 12.5 kHz",
292ccae7af2SMauro Carvalho Chehab 	};
293ccae7af2SMauro Carvalho Chehab 	tuner_info("read: 0x%2x\n", buf[0]);
294ccae7af2SMauro Carvalho Chehab 	tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
295ccae7af2SMauro Carvalho Chehab 	tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
296ccae7af2SMauro Carvalho Chehab 	tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
297ccae7af2SMauro Carvalho Chehab 	tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
298ccae7af2SMauro Carvalho Chehab 	tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
299ccae7af2SMauro Carvalho Chehab }
300ccae7af2SMauro Carvalho Chehab 
dump_write_message(struct dvb_frontend * fe,unsigned char * buf)301ccae7af2SMauro Carvalho Chehab static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
302ccae7af2SMauro Carvalho Chehab {
303ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
304ccae7af2SMauro Carvalho Chehab 
305ccae7af2SMauro Carvalho Chehab 	static char *sound[4] = {
306ccae7af2SMauro Carvalho Chehab 		"AM/TV",
307ccae7af2SMauro Carvalho Chehab 		"FM/radio",
308ccae7af2SMauro Carvalho Chehab 		"FM/TV",
309ccae7af2SMauro Carvalho Chehab 		"FM/radio"
310ccae7af2SMauro Carvalho Chehab 	};
311ccae7af2SMauro Carvalho Chehab 	static char *adjust[32] = {
312ccae7af2SMauro Carvalho Chehab 		"-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
313ccae7af2SMauro Carvalho Chehab 		"-8",  "-7",  "-6",  "-5",  "-4",  "-3",  "-2",  "-1",
314ccae7af2SMauro Carvalho Chehab 		"0",   "+1",  "+2",  "+3",  "+4",  "+5",  "+6",  "+7",
315ccae7af2SMauro Carvalho Chehab 		"+8",  "+9",  "+10", "+11", "+12", "+13", "+14", "+15"
316ccae7af2SMauro Carvalho Chehab 	};
317ccae7af2SMauro Carvalho Chehab 	static char *deemph[4] = {
318ccae7af2SMauro Carvalho Chehab 		"no", "no", "75", "50"
319ccae7af2SMauro Carvalho Chehab 	};
320ccae7af2SMauro Carvalho Chehab 	static char *carrier[4] = {
321ccae7af2SMauro Carvalho Chehab 		"4.5 MHz",
322ccae7af2SMauro Carvalho Chehab 		"5.5 MHz",
323ccae7af2SMauro Carvalho Chehab 		"6.0 MHz",
324ccae7af2SMauro Carvalho Chehab 		"6.5 MHz / AM"
325ccae7af2SMauro Carvalho Chehab 	};
326ccae7af2SMauro Carvalho Chehab 	static char *vif[8] = {
327ccae7af2SMauro Carvalho Chehab 		"58.75 MHz",
328ccae7af2SMauro Carvalho Chehab 		"45.75 MHz",
329ccae7af2SMauro Carvalho Chehab 		"38.9 MHz",
330ccae7af2SMauro Carvalho Chehab 		"38.0 MHz",
331ccae7af2SMauro Carvalho Chehab 		"33.9 MHz",
332ccae7af2SMauro Carvalho Chehab 		"33.4 MHz",
333ccae7af2SMauro Carvalho Chehab 		"45.75 MHz + pin13",
334ccae7af2SMauro Carvalho Chehab 		"38.9 MHz + pin13",
335ccae7af2SMauro Carvalho Chehab 	};
336ccae7af2SMauro Carvalho Chehab 	static char *rif[4] = {
337ccae7af2SMauro Carvalho Chehab 		"44 MHz",
338ccae7af2SMauro Carvalho Chehab 		"52 MHz",
339ccae7af2SMauro Carvalho Chehab 		"52 MHz",
340ccae7af2SMauro Carvalho Chehab 		"44 MHz",
341ccae7af2SMauro Carvalho Chehab 	};
342ccae7af2SMauro Carvalho Chehab 
343ccae7af2SMauro Carvalho Chehab 	tuner_info("write: byte B 0x%02x\n", buf[1]);
344ccae7af2SMauro Carvalho Chehab 	tuner_info("  B0   video mode      : %s\n",
345ccae7af2SMauro Carvalho Chehab 		   (buf[1] & 0x01) ? "video trap" : "sound trap");
346ccae7af2SMauro Carvalho Chehab 	tuner_info("  B1   auto mute fm    : %s\n",
347ccae7af2SMauro Carvalho Chehab 		   (buf[1] & 0x02) ? "yes" : "no");
348ccae7af2SMauro Carvalho Chehab 	tuner_info("  B2   carrier mode    : %s\n",
349ccae7af2SMauro Carvalho Chehab 		   (buf[1] & 0x04) ? "QSS" : "Intercarrier");
350ccae7af2SMauro Carvalho Chehab 	tuner_info("  B3-4 tv sound/radio  : %s\n",
351ccae7af2SMauro Carvalho Chehab 		   sound[(buf[1] & 0x18) >> 3]);
352ccae7af2SMauro Carvalho Chehab 	tuner_info("  B5   force mute audio: %s\n",
353ccae7af2SMauro Carvalho Chehab 		   (buf[1] & 0x20) ? "yes" : "no");
354ccae7af2SMauro Carvalho Chehab 	tuner_info("  B6   output port 1   : %s\n",
355ccae7af2SMauro Carvalho Chehab 		   (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
356ccae7af2SMauro Carvalho Chehab 	tuner_info("  B7   output port 2   : %s\n",
357ccae7af2SMauro Carvalho Chehab 		   (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
358ccae7af2SMauro Carvalho Chehab 
359ccae7af2SMauro Carvalho Chehab 	tuner_info("write: byte C 0x%02x\n", buf[2]);
360ccae7af2SMauro Carvalho Chehab 	tuner_info("  C0-4 top adjustment  : %s dB\n",
361ccae7af2SMauro Carvalho Chehab 		   adjust[buf[2] & 0x1f]);
362ccae7af2SMauro Carvalho Chehab 	tuner_info("  C5-6 de-emphasis     : %s\n",
363ccae7af2SMauro Carvalho Chehab 		   deemph[(buf[2] & 0x60) >> 5]);
364ccae7af2SMauro Carvalho Chehab 	tuner_info("  C7   audio gain      : %s\n",
365ccae7af2SMauro Carvalho Chehab 		   (buf[2] & 0x80) ? "-6" : "0");
366ccae7af2SMauro Carvalho Chehab 
367ccae7af2SMauro Carvalho Chehab 	tuner_info("write: byte E 0x%02x\n", buf[3]);
368ccae7af2SMauro Carvalho Chehab 	tuner_info("  E0-1 sound carrier   : %s\n",
369ccae7af2SMauro Carvalho Chehab 		   carrier[(buf[3] & 0x03)]);
370ccae7af2SMauro Carvalho Chehab 	tuner_info("  E6   l pll gating   : %s\n",
371ccae7af2SMauro Carvalho Chehab 		   (buf[3] & 0x40) ? "36" : "13");
372ccae7af2SMauro Carvalho Chehab 
373ccae7af2SMauro Carvalho Chehab 	if (buf[1] & 0x08) {
374ccae7af2SMauro Carvalho Chehab 		/* radio */
375ccae7af2SMauro Carvalho Chehab 		tuner_info("  E2-4 video if        : %s\n",
376ccae7af2SMauro Carvalho Chehab 			   rif[(buf[3] & 0x0c) >> 2]);
377ccae7af2SMauro Carvalho Chehab 		tuner_info("  E7   vif agc output  : %s\n",
378ccae7af2SMauro Carvalho Chehab 			   (buf[3] & 0x80)
379ccae7af2SMauro Carvalho Chehab 			   ? ((buf[3] & 0x10) ? "fm-agc radio" :
380ccae7af2SMauro Carvalho Chehab 						"sif-agc radio")
381ccae7af2SMauro Carvalho Chehab 			   : "fm radio carrier afc");
382ccae7af2SMauro Carvalho Chehab 	} else {
383ccae7af2SMauro Carvalho Chehab 		/* video */
384ccae7af2SMauro Carvalho Chehab 		tuner_info("  E2-4 video if        : %s\n",
385ccae7af2SMauro Carvalho Chehab 			   vif[(buf[3] & 0x1c) >> 2]);
386ccae7af2SMauro Carvalho Chehab 		tuner_info("  E5   tuner gain      : %s\n",
387ccae7af2SMauro Carvalho Chehab 			   (buf[3] & 0x80)
388ccae7af2SMauro Carvalho Chehab 			   ? ((buf[3] & 0x20) ? "external" : "normal")
389ccae7af2SMauro Carvalho Chehab 			   : ((buf[3] & 0x20) ? "minimum"  : "normal"));
390ccae7af2SMauro Carvalho Chehab 		tuner_info("  E7   vif agc output  : %s\n",
391ccae7af2SMauro Carvalho Chehab 			   (buf[3] & 0x80) ? ((buf[3] & 0x20)
392ccae7af2SMauro Carvalho Chehab 				? "pin3 port, pin22 vif agc out"
393ccae7af2SMauro Carvalho Chehab 				: "pin22 port, pin3 vif acg ext in")
394ccae7af2SMauro Carvalho Chehab 				: "pin3+pin22 port");
395ccae7af2SMauro Carvalho Chehab 	}
396ccae7af2SMauro Carvalho Chehab 	tuner_info("--\n");
397ccae7af2SMauro Carvalho Chehab }
398ccae7af2SMauro Carvalho Chehab 
399ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
400ccae7af2SMauro Carvalho Chehab 
tda9887_set_tvnorm(struct dvb_frontend * fe)401ccae7af2SMauro Carvalho Chehab static int tda9887_set_tvnorm(struct dvb_frontend *fe)
402ccae7af2SMauro Carvalho Chehab {
403ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
404ccae7af2SMauro Carvalho Chehab 	struct tvnorm *norm = NULL;
405ccae7af2SMauro Carvalho Chehab 	char *buf = priv->data;
406ccae7af2SMauro Carvalho Chehab 	int i;
407ccae7af2SMauro Carvalho Chehab 
408ccae7af2SMauro Carvalho Chehab 	if (priv->mode == V4L2_TUNER_RADIO) {
409ccae7af2SMauro Carvalho Chehab 		if (priv->audmode == V4L2_TUNER_MODE_MONO)
410ccae7af2SMauro Carvalho Chehab 			norm = &radio_mono;
411ccae7af2SMauro Carvalho Chehab 		else
412ccae7af2SMauro Carvalho Chehab 			norm = &radio_stereo;
413ccae7af2SMauro Carvalho Chehab 	} else {
414ccae7af2SMauro Carvalho Chehab 		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
415ccae7af2SMauro Carvalho Chehab 			if (tvnorms[i].std & priv->std) {
416ccae7af2SMauro Carvalho Chehab 				norm = tvnorms+i;
417ccae7af2SMauro Carvalho Chehab 				break;
418ccae7af2SMauro Carvalho Chehab 			}
419ccae7af2SMauro Carvalho Chehab 		}
420ccae7af2SMauro Carvalho Chehab 	}
421ccae7af2SMauro Carvalho Chehab 	if (NULL == norm) {
422ccae7af2SMauro Carvalho Chehab 		tuner_dbg("Unsupported tvnorm entry - audio muted\n");
423ccae7af2SMauro Carvalho Chehab 		return -1;
424ccae7af2SMauro Carvalho Chehab 	}
425ccae7af2SMauro Carvalho Chehab 
426ccae7af2SMauro Carvalho Chehab 	tuner_dbg("configure for: %s\n", norm->name);
427ccae7af2SMauro Carvalho Chehab 	buf[1] = norm->b;
428ccae7af2SMauro Carvalho Chehab 	buf[2] = norm->c;
429ccae7af2SMauro Carvalho Chehab 	buf[3] = norm->e;
430ccae7af2SMauro Carvalho Chehab 	return 0;
431ccae7af2SMauro Carvalho Chehab }
432ccae7af2SMauro Carvalho Chehab 
433ccae7af2SMauro Carvalho Chehab static unsigned int port1  = UNSET;
434ccae7af2SMauro Carvalho Chehab static unsigned int port2  = UNSET;
435ccae7af2SMauro Carvalho Chehab static unsigned int qss    = UNSET;
436ccae7af2SMauro Carvalho Chehab static unsigned int adjust = UNSET;
437ccae7af2SMauro Carvalho Chehab 
438ccae7af2SMauro Carvalho Chehab module_param(port1, int, 0644);
439ccae7af2SMauro Carvalho Chehab module_param(port2, int, 0644);
440ccae7af2SMauro Carvalho Chehab module_param(qss, int, 0644);
441ccae7af2SMauro Carvalho Chehab module_param(adjust, int, 0644);
442ccae7af2SMauro Carvalho Chehab 
tda9887_set_insmod(struct dvb_frontend * fe)443ccae7af2SMauro Carvalho Chehab static int tda9887_set_insmod(struct dvb_frontend *fe)
444ccae7af2SMauro Carvalho Chehab {
445ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
446ccae7af2SMauro Carvalho Chehab 	char *buf = priv->data;
447ccae7af2SMauro Carvalho Chehab 
448ccae7af2SMauro Carvalho Chehab 	if (UNSET != port1) {
449ccae7af2SMauro Carvalho Chehab 		if (port1)
450ccae7af2SMauro Carvalho Chehab 			buf[1] |= cOutputPort1Inactive;
451ccae7af2SMauro Carvalho Chehab 		else
452ccae7af2SMauro Carvalho Chehab 			buf[1] &= ~cOutputPort1Inactive;
453ccae7af2SMauro Carvalho Chehab 	}
454ccae7af2SMauro Carvalho Chehab 	if (UNSET != port2) {
455ccae7af2SMauro Carvalho Chehab 		if (port2)
456ccae7af2SMauro Carvalho Chehab 			buf[1] |= cOutputPort2Inactive;
457ccae7af2SMauro Carvalho Chehab 		else
458ccae7af2SMauro Carvalho Chehab 			buf[1] &= ~cOutputPort2Inactive;
459ccae7af2SMauro Carvalho Chehab 	}
460ccae7af2SMauro Carvalho Chehab 
461ccae7af2SMauro Carvalho Chehab 	if (UNSET != qss) {
462ccae7af2SMauro Carvalho Chehab 		if (qss)
463ccae7af2SMauro Carvalho Chehab 			buf[1] |= cQSS;
464ccae7af2SMauro Carvalho Chehab 		else
465ccae7af2SMauro Carvalho Chehab 			buf[1] &= ~cQSS;
466ccae7af2SMauro Carvalho Chehab 	}
467ccae7af2SMauro Carvalho Chehab 
468ccae7af2SMauro Carvalho Chehab 	if (adjust < 0x20) {
469ccae7af2SMauro Carvalho Chehab 		buf[2] &= ~cTopMask;
470ccae7af2SMauro Carvalho Chehab 		buf[2] |= adjust;
471ccae7af2SMauro Carvalho Chehab 	}
472ccae7af2SMauro Carvalho Chehab 	return 0;
473ccae7af2SMauro Carvalho Chehab }
474ccae7af2SMauro Carvalho Chehab 
tda9887_do_config(struct dvb_frontend * fe)475ccae7af2SMauro Carvalho Chehab static int tda9887_do_config(struct dvb_frontend *fe)
476ccae7af2SMauro Carvalho Chehab {
477ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
478ccae7af2SMauro Carvalho Chehab 	char *buf = priv->data;
479ccae7af2SMauro Carvalho Chehab 
480ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_PORT1_ACTIVE)
481ccae7af2SMauro Carvalho Chehab 		buf[1] &= ~cOutputPort1Inactive;
482ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_PORT1_INACTIVE)
483ccae7af2SMauro Carvalho Chehab 		buf[1] |= cOutputPort1Inactive;
484ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_PORT2_ACTIVE)
485ccae7af2SMauro Carvalho Chehab 		buf[1] &= ~cOutputPort2Inactive;
486ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_PORT2_INACTIVE)
487ccae7af2SMauro Carvalho Chehab 		buf[1] |= cOutputPort2Inactive;
488ccae7af2SMauro Carvalho Chehab 
489ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_QSS)
490ccae7af2SMauro Carvalho Chehab 		buf[1] |= cQSS;
491ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_INTERCARRIER)
492ccae7af2SMauro Carvalho Chehab 		buf[1] &= ~cQSS;
493ccae7af2SMauro Carvalho Chehab 
494ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_AUTOMUTE)
495ccae7af2SMauro Carvalho Chehab 		buf[1] |= cAutoMuteFmActive;
496ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_DEEMPHASIS_MASK) {
497ccae7af2SMauro Carvalho Chehab 		buf[2] &= ~0x60;
498ccae7af2SMauro Carvalho Chehab 		switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
499ccae7af2SMauro Carvalho Chehab 		case TDA9887_DEEMPHASIS_NONE:
500ccae7af2SMauro Carvalho Chehab 			buf[2] |= cDeemphasisOFF;
501ccae7af2SMauro Carvalho Chehab 			break;
502ccae7af2SMauro Carvalho Chehab 		case TDA9887_DEEMPHASIS_50:
503ccae7af2SMauro Carvalho Chehab 			buf[2] |= cDeemphasisON | cDeemphasis50;
504ccae7af2SMauro Carvalho Chehab 			break;
505ccae7af2SMauro Carvalho Chehab 		case TDA9887_DEEMPHASIS_75:
506ccae7af2SMauro Carvalho Chehab 			buf[2] |= cDeemphasisON | cDeemphasis75;
507ccae7af2SMauro Carvalho Chehab 			break;
508ccae7af2SMauro Carvalho Chehab 		}
509ccae7af2SMauro Carvalho Chehab 	}
510ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_TOP_SET) {
511ccae7af2SMauro Carvalho Chehab 		buf[2] &= ~cTopMask;
512ccae7af2SMauro Carvalho Chehab 		buf[2] |= (priv->config >> 8) & cTopMask;
513ccae7af2SMauro Carvalho Chehab 	}
514ccae7af2SMauro Carvalho Chehab 	if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
515ccae7af2SMauro Carvalho Chehab 	    (priv->std & V4L2_STD_NTSC))
516ccae7af2SMauro Carvalho Chehab 		buf[1] &= ~cQSS;
517ccae7af2SMauro Carvalho Chehab 	if (priv->config & TDA9887_GATING_18)
518ccae7af2SMauro Carvalho Chehab 		buf[3] &= ~cGating_36;
519ccae7af2SMauro Carvalho Chehab 
520ccae7af2SMauro Carvalho Chehab 	if (priv->mode == V4L2_TUNER_RADIO) {
521ccae7af2SMauro Carvalho Chehab 		if (priv->config & TDA9887_RIF_41_3) {
522ccae7af2SMauro Carvalho Chehab 			buf[3] &= ~cVideoIFMask;
523ccae7af2SMauro Carvalho Chehab 			buf[3] |= cRadioIF_41_30;
524ccae7af2SMauro Carvalho Chehab 		}
525ccae7af2SMauro Carvalho Chehab 		if (priv->config & TDA9887_GAIN_NORMAL)
526ccae7af2SMauro Carvalho Chehab 			buf[3] &= ~cTunerGainLow;
527ccae7af2SMauro Carvalho Chehab 	}
528ccae7af2SMauro Carvalho Chehab 
529ccae7af2SMauro Carvalho Chehab 	return 0;
530ccae7af2SMauro Carvalho Chehab }
531ccae7af2SMauro Carvalho Chehab 
532ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
533ccae7af2SMauro Carvalho Chehab 
tda9887_status(struct dvb_frontend * fe)534ccae7af2SMauro Carvalho Chehab static int tda9887_status(struct dvb_frontend *fe)
535ccae7af2SMauro Carvalho Chehab {
536ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
537ccae7af2SMauro Carvalho Chehab 	unsigned char buf[1];
538ccae7af2SMauro Carvalho Chehab 	int rc;
539ccae7af2SMauro Carvalho Chehab 
540408679cdSMauro Carvalho Chehab 	rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1);
541408679cdSMauro Carvalho Chehab 	if (rc != 1)
542ccae7af2SMauro Carvalho Chehab 		tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
543ccae7af2SMauro Carvalho Chehab 	dump_read_message(fe, buf);
544ccae7af2SMauro Carvalho Chehab 	return 0;
545ccae7af2SMauro Carvalho Chehab }
546ccae7af2SMauro Carvalho Chehab 
tda9887_configure(struct dvb_frontend * fe)547ccae7af2SMauro Carvalho Chehab static void tda9887_configure(struct dvb_frontend *fe)
548ccae7af2SMauro Carvalho Chehab {
549ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
550ccae7af2SMauro Carvalho Chehab 	int rc;
551ccae7af2SMauro Carvalho Chehab 
552ccae7af2SMauro Carvalho Chehab 	memset(priv->data,0,sizeof(priv->data));
553ccae7af2SMauro Carvalho Chehab 	tda9887_set_tvnorm(fe);
554ccae7af2SMauro Carvalho Chehab 
555ccae7af2SMauro Carvalho Chehab 	/* A note on the port settings:
556ccae7af2SMauro Carvalho Chehab 	   These settings tend to depend on the specifics of the board.
557ccae7af2SMauro Carvalho Chehab 	   By default they are set to inactive (bit value 1) by this driver,
558ccae7af2SMauro Carvalho Chehab 	   overwriting any changes made by the tvnorm. This means that it
559ccae7af2SMauro Carvalho Chehab 	   is the responsibility of the module using the tda9887 to set
560ccae7af2SMauro Carvalho Chehab 	   these values in case of changes in the tvnorm.
561ccae7af2SMauro Carvalho Chehab 	   In many cases port 2 should be made active (0) when selecting
562ccae7af2SMauro Carvalho Chehab 	   SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
563ccae7af2SMauro Carvalho Chehab 
564ccae7af2SMauro Carvalho Chehab 	   For the other standards the tda9887 application note says that
565ccae7af2SMauro Carvalho Chehab 	   the ports should be set to active (0), but, again, that may
566ccae7af2SMauro Carvalho Chehab 	   differ depending on the precise hardware configuration.
567ccae7af2SMauro Carvalho Chehab 	 */
568ccae7af2SMauro Carvalho Chehab 	priv->data[1] |= cOutputPort1Inactive;
569ccae7af2SMauro Carvalho Chehab 	priv->data[1] |= cOutputPort2Inactive;
570ccae7af2SMauro Carvalho Chehab 
571ccae7af2SMauro Carvalho Chehab 	tda9887_do_config(fe);
572ccae7af2SMauro Carvalho Chehab 	tda9887_set_insmod(fe);
573ccae7af2SMauro Carvalho Chehab 
574ccae7af2SMauro Carvalho Chehab 	if (priv->standby)
575ccae7af2SMauro Carvalho Chehab 		priv->data[1] |= cForcedMuteAudioON;
576ccae7af2SMauro Carvalho Chehab 
577ccae7af2SMauro Carvalho Chehab 	tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
578ccae7af2SMauro Carvalho Chehab 		  priv->data[1], priv->data[2], priv->data[3]);
579ccae7af2SMauro Carvalho Chehab 	if (debug > 1)
580ccae7af2SMauro Carvalho Chehab 		dump_write_message(fe, priv->data);
581ccae7af2SMauro Carvalho Chehab 
582ccae7af2SMauro Carvalho Chehab 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
583ccae7af2SMauro Carvalho Chehab 		tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
584ccae7af2SMauro Carvalho Chehab 
585ccae7af2SMauro Carvalho Chehab 	if (debug > 2) {
586ccae7af2SMauro Carvalho Chehab 		msleep_interruptible(1000);
587ccae7af2SMauro Carvalho Chehab 		tda9887_status(fe);
588ccae7af2SMauro Carvalho Chehab 	}
589ccae7af2SMauro Carvalho Chehab }
590ccae7af2SMauro Carvalho Chehab 
591ccae7af2SMauro Carvalho Chehab /* ---------------------------------------------------------------------- */
592ccae7af2SMauro Carvalho Chehab 
tda9887_tuner_status(struct dvb_frontend * fe)593ccae7af2SMauro Carvalho Chehab static void tda9887_tuner_status(struct dvb_frontend *fe)
594ccae7af2SMauro Carvalho Chehab {
595ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
596ccae7af2SMauro Carvalho Chehab 	tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
597ccae7af2SMauro Carvalho Chehab 		   priv->data[1], priv->data[2], priv->data[3]);
598ccae7af2SMauro Carvalho Chehab }
599ccae7af2SMauro Carvalho Chehab 
tda9887_get_afc(struct dvb_frontend * fe,s32 * afc)600a2192cf4SHans Verkuil static int tda9887_get_afc(struct dvb_frontend *fe, s32 *afc)
601ccae7af2SMauro Carvalho Chehab {
602ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
603a2192cf4SHans Verkuil 	static const int AFC_BITS_2_kHz[] = {
604ccae7af2SMauro Carvalho Chehab 		-12500,  -37500,  -62500,  -97500,
605ccae7af2SMauro Carvalho Chehab 		-112500, -137500, -162500, -187500,
606ccae7af2SMauro Carvalho Chehab 		187500,  162500,  137500,  112500,
607ccae7af2SMauro Carvalho Chehab 		97500 ,  62500,   37500 ,  12500
608ccae7af2SMauro Carvalho Chehab 	};
609ccae7af2SMauro Carvalho Chehab 	__u8 reg = 0;
610ccae7af2SMauro Carvalho Chehab 
611a2192cf4SHans Verkuil 	if (priv->mode != V4L2_TUNER_RADIO)
612a2192cf4SHans Verkuil 		return 0;
613ccae7af2SMauro Carvalho Chehab 	if (1 == tuner_i2c_xfer_recv(&priv->i2c_props, &reg, 1))
614a2192cf4SHans Verkuil 		*afc = AFC_BITS_2_kHz[(reg >> 1) & 0x0f];
615a2192cf4SHans Verkuil 	return 0;
616ccae7af2SMauro Carvalho Chehab }
617ccae7af2SMauro Carvalho Chehab 
tda9887_standby(struct dvb_frontend * fe)618ccae7af2SMauro Carvalho Chehab static void tda9887_standby(struct dvb_frontend *fe)
619ccae7af2SMauro Carvalho Chehab {
620ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
621ccae7af2SMauro Carvalho Chehab 
622ccae7af2SMauro Carvalho Chehab 	priv->standby = true;
623ccae7af2SMauro Carvalho Chehab 
624ccae7af2SMauro Carvalho Chehab 	tda9887_configure(fe);
625ccae7af2SMauro Carvalho Chehab }
626ccae7af2SMauro Carvalho Chehab 
tda9887_set_params(struct dvb_frontend * fe,struct analog_parameters * params)627ccae7af2SMauro Carvalho Chehab static void tda9887_set_params(struct dvb_frontend *fe,
628ccae7af2SMauro Carvalho Chehab 			       struct analog_parameters *params)
629ccae7af2SMauro Carvalho Chehab {
630ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
631ccae7af2SMauro Carvalho Chehab 
632ccae7af2SMauro Carvalho Chehab 	priv->standby = false;
633ccae7af2SMauro Carvalho Chehab 	priv->mode    = params->mode;
634ccae7af2SMauro Carvalho Chehab 	priv->audmode = params->audmode;
635ccae7af2SMauro Carvalho Chehab 	priv->std     = params->std;
636ccae7af2SMauro Carvalho Chehab 	tda9887_configure(fe);
637ccae7af2SMauro Carvalho Chehab }
638ccae7af2SMauro Carvalho Chehab 
tda9887_set_config(struct dvb_frontend * fe,void * priv_cfg)639ccae7af2SMauro Carvalho Chehab static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
640ccae7af2SMauro Carvalho Chehab {
641ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
642ccae7af2SMauro Carvalho Chehab 
643ccae7af2SMauro Carvalho Chehab 	priv->config = *(unsigned int *)priv_cfg;
644ccae7af2SMauro Carvalho Chehab 	tda9887_configure(fe);
645ccae7af2SMauro Carvalho Chehab 
646ccae7af2SMauro Carvalho Chehab 	return 0;
647ccae7af2SMauro Carvalho Chehab }
648ccae7af2SMauro Carvalho Chehab 
tda9887_release(struct dvb_frontend * fe)649ccae7af2SMauro Carvalho Chehab static void tda9887_release(struct dvb_frontend *fe)
650ccae7af2SMauro Carvalho Chehab {
651ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = fe->analog_demod_priv;
652ccae7af2SMauro Carvalho Chehab 
653ccae7af2SMauro Carvalho Chehab 	mutex_lock(&tda9887_list_mutex);
654ccae7af2SMauro Carvalho Chehab 
655ccae7af2SMauro Carvalho Chehab 	if (priv)
656ccae7af2SMauro Carvalho Chehab 		hybrid_tuner_release_state(priv);
657ccae7af2SMauro Carvalho Chehab 
658ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&tda9887_list_mutex);
659ccae7af2SMauro Carvalho Chehab 
660ccae7af2SMauro Carvalho Chehab 	fe->analog_demod_priv = NULL;
661ccae7af2SMauro Carvalho Chehab }
662ccae7af2SMauro Carvalho Chehab 
663bd336e63SMax Kellermann static const struct analog_demod_ops tda9887_ops = {
664ccae7af2SMauro Carvalho Chehab 	.info		= {
665ccae7af2SMauro Carvalho Chehab 		.name	= "tda9887",
666ccae7af2SMauro Carvalho Chehab 	},
667ccae7af2SMauro Carvalho Chehab 	.set_params     = tda9887_set_params,
668ccae7af2SMauro Carvalho Chehab 	.standby        = tda9887_standby,
669ccae7af2SMauro Carvalho Chehab 	.tuner_status   = tda9887_tuner_status,
670ccae7af2SMauro Carvalho Chehab 	.get_afc        = tda9887_get_afc,
671ccae7af2SMauro Carvalho Chehab 	.release        = tda9887_release,
672ccae7af2SMauro Carvalho Chehab 	.set_config     = tda9887_set_config,
673ccae7af2SMauro Carvalho Chehab };
674ccae7af2SMauro Carvalho Chehab 
tda9887_attach(struct dvb_frontend * fe,struct i2c_adapter * i2c_adap,u8 i2c_addr)675ccae7af2SMauro Carvalho Chehab struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
676ccae7af2SMauro Carvalho Chehab 				    struct i2c_adapter *i2c_adap,
677ccae7af2SMauro Carvalho Chehab 				    u8 i2c_addr)
678ccae7af2SMauro Carvalho Chehab {
679ccae7af2SMauro Carvalho Chehab 	struct tda9887_priv *priv = NULL;
680ccae7af2SMauro Carvalho Chehab 	int instance;
681ccae7af2SMauro Carvalho Chehab 
682ccae7af2SMauro Carvalho Chehab 	mutex_lock(&tda9887_list_mutex);
683ccae7af2SMauro Carvalho Chehab 
684ccae7af2SMauro Carvalho Chehab 	instance = hybrid_tuner_request_state(struct tda9887_priv, priv,
685ccae7af2SMauro Carvalho Chehab 					      hybrid_tuner_instance_list,
686ccae7af2SMauro Carvalho Chehab 					      i2c_adap, i2c_addr, "tda9887");
687ccae7af2SMauro Carvalho Chehab 	switch (instance) {
688ccae7af2SMauro Carvalho Chehab 	case 0:
689ccae7af2SMauro Carvalho Chehab 		mutex_unlock(&tda9887_list_mutex);
690ccae7af2SMauro Carvalho Chehab 		return NULL;
691ccae7af2SMauro Carvalho Chehab 	case 1:
692ccae7af2SMauro Carvalho Chehab 		fe->analog_demod_priv = priv;
693ccae7af2SMauro Carvalho Chehab 		priv->standby = true;
694ccae7af2SMauro Carvalho Chehab 		tuner_info("tda988[5/6/7] found\n");
695ccae7af2SMauro Carvalho Chehab 		break;
696ccae7af2SMauro Carvalho Chehab 	default:
697ccae7af2SMauro Carvalho Chehab 		fe->analog_demod_priv = priv;
698ccae7af2SMauro Carvalho Chehab 		break;
699ccae7af2SMauro Carvalho Chehab 	}
700ccae7af2SMauro Carvalho Chehab 
701ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&tda9887_list_mutex);
702ccae7af2SMauro Carvalho Chehab 
703ccae7af2SMauro Carvalho Chehab 	memcpy(&fe->ops.analog_ops, &tda9887_ops,
704ccae7af2SMauro Carvalho Chehab 	       sizeof(struct analog_demod_ops));
705ccae7af2SMauro Carvalho Chehab 
706ccae7af2SMauro Carvalho Chehab 	return fe;
707ccae7af2SMauro Carvalho Chehab }
708ccae7af2SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(tda9887_attach);
709ccae7af2SMauro Carvalho Chehab 
710ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL");
711