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, ®, 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