1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * i2c tv tuner chip device driver
4*4882a593Smuzhiyun * controls all those simple 4-control-bytes style tuners.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This "tuner-simple" module was split apart from the original "tuner" module.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/i2c.h>
10*4882a593Smuzhiyun #include <linux/videodev2.h>
11*4882a593Smuzhiyun #include <media/tuner.h>
12*4882a593Smuzhiyun #include <media/v4l2-common.h>
13*4882a593Smuzhiyun #include <media/tuner-types.h>
14*4882a593Smuzhiyun #include "tuner-i2c.h"
15*4882a593Smuzhiyun #include "tuner-simple.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun static int debug;
18*4882a593Smuzhiyun module_param(debug, int, 0644);
19*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "enable verbose debug messages");
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define TUNER_SIMPLE_MAX 64
22*4882a593Smuzhiyun static unsigned int simple_devcount;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun static int offset;
25*4882a593Smuzhiyun module_param(offset, int, 0664);
26*4882a593Smuzhiyun MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
29*4882a593Smuzhiyun { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
30*4882a593Smuzhiyun static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
31*4882a593Smuzhiyun { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
32*4882a593Smuzhiyun module_param_array(atv_input, int, NULL, 0644);
33*4882a593Smuzhiyun module_param_array(dtv_input, int, NULL, 0644);
34*4882a593Smuzhiyun MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
35*4882a593Smuzhiyun MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* ---------------------------------------------------------------------- */
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /* tv standard selection for Temic 4046 FM5
40*4882a593Smuzhiyun this value takes the low bits of control byte 2
41*4882a593Smuzhiyun from datasheet Rev.01, Feb.00
42*4882a593Smuzhiyun standard BG I L L2 D
43*4882a593Smuzhiyun picture IF 38.9 38.9 38.9 33.95 38.9
44*4882a593Smuzhiyun sound 1 33.4 32.9 32.4 40.45 32.4
45*4882a593Smuzhiyun sound 2 33.16
46*4882a593Smuzhiyun NICAM 33.05 32.348 33.05 33.05
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun #define TEMIC_SET_PAL_I 0x05
49*4882a593Smuzhiyun #define TEMIC_SET_PAL_DK 0x09
50*4882a593Smuzhiyun #define TEMIC_SET_PAL_L 0x0a /* SECAM ? */
51*4882a593Smuzhiyun #define TEMIC_SET_PAL_L2 0x0b /* change IF ! */
52*4882a593Smuzhiyun #define TEMIC_SET_PAL_BG 0x0c
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* tv tuner system standard selection for Philips FQ1216ME
55*4882a593Smuzhiyun this value takes the low bits of control byte 2
56*4882a593Smuzhiyun from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
57*4882a593Smuzhiyun standard BG DK I L L`
58*4882a593Smuzhiyun picture carrier 38.90 38.90 38.90 38.90 33.95
59*4882a593Smuzhiyun colour 34.47 34.47 34.47 34.47 38.38
60*4882a593Smuzhiyun sound 1 33.40 32.40 32.90 32.40 40.45
61*4882a593Smuzhiyun sound 2 33.16 - - - -
62*4882a593Smuzhiyun NICAM 33.05 33.05 32.35 33.05 39.80
63*4882a593Smuzhiyun */
64*4882a593Smuzhiyun #define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/
65*4882a593Smuzhiyun #define PHILIPS_SET_PAL_BGDK 0x09
66*4882a593Smuzhiyun #define PHILIPS_SET_PAL_L2 0x0a
67*4882a593Smuzhiyun #define PHILIPS_SET_PAL_L 0x0b
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* system switching for Philips FI1216MF MK2
70*4882a593Smuzhiyun from datasheet "1996 Jul 09",
71*4882a593Smuzhiyun standard BG L L'
72*4882a593Smuzhiyun picture carrier 38.90 38.90 33.95
73*4882a593Smuzhiyun colour 34.47 34.37 38.38
74*4882a593Smuzhiyun sound 1 33.40 32.40 40.45
75*4882a593Smuzhiyun sound 2 33.16 - -
76*4882a593Smuzhiyun NICAM 33.05 33.05 39.80
77*4882a593Smuzhiyun */
78*4882a593Smuzhiyun #define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
79*4882a593Smuzhiyun #define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */
80*4882a593Smuzhiyun #define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* Control byte */
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun #define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */
85*4882a593Smuzhiyun #define TUNER_RATIO_SELECT_50 0x00
86*4882a593Smuzhiyun #define TUNER_RATIO_SELECT_32 0x02
87*4882a593Smuzhiyun #define TUNER_RATIO_SELECT_166 0x04
88*4882a593Smuzhiyun #define TUNER_RATIO_SELECT_62 0x06
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun #define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /* Status byte */
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun #define TUNER_POR 0x80
95*4882a593Smuzhiyun #define TUNER_FL 0x40
96*4882a593Smuzhiyun #define TUNER_MODE 0x38
97*4882a593Smuzhiyun #define TUNER_AFC 0x07
98*4882a593Smuzhiyun #define TUNER_SIGNAL 0x07
99*4882a593Smuzhiyun #define TUNER_STEREO 0x10
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun #define TUNER_PLL_LOCKED 0x40
102*4882a593Smuzhiyun #define TUNER_STEREO_MK3 0x04
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun static DEFINE_MUTEX(tuner_simple_list_mutex);
105*4882a593Smuzhiyun static LIST_HEAD(hybrid_tuner_instance_list);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun struct tuner_simple_priv {
108*4882a593Smuzhiyun unsigned int nr;
109*4882a593Smuzhiyun u16 last_div;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun struct tuner_i2c_props i2c_props;
112*4882a593Smuzhiyun struct list_head hybrid_tuner_instance_list;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun unsigned int type;
115*4882a593Smuzhiyun struct tunertype *tun;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun u32 frequency;
118*4882a593Smuzhiyun u32 bandwidth;
119*4882a593Smuzhiyun bool radio_mode;
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* ---------------------------------------------------------------------- */
123*4882a593Smuzhiyun
tuner_read_status(struct dvb_frontend * fe)124*4882a593Smuzhiyun static int tuner_read_status(struct dvb_frontend *fe)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
127*4882a593Smuzhiyun unsigned char byte;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
130*4882a593Smuzhiyun return 0;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun return byte;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
tuner_signal(const int status)135*4882a593Smuzhiyun static inline int tuner_signal(const int status)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun return (status & TUNER_SIGNAL) << 13;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
tuner_stereo(const int type,const int status)140*4882a593Smuzhiyun static inline int tuner_stereo(const int type, const int status)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun switch (type) {
143*4882a593Smuzhiyun case TUNER_PHILIPS_FM1216ME_MK3:
144*4882a593Smuzhiyun case TUNER_PHILIPS_FM1236_MK3:
145*4882a593Smuzhiyun case TUNER_PHILIPS_FM1256_IH3:
146*4882a593Smuzhiyun case TUNER_LG_NTSC_TAPE:
147*4882a593Smuzhiyun case TUNER_TCL_MF02GIP_5N:
148*4882a593Smuzhiyun return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
149*4882a593Smuzhiyun case TUNER_PHILIPS_FM1216MK5:
150*4882a593Smuzhiyun return status | TUNER_STEREO;
151*4882a593Smuzhiyun default:
152*4882a593Smuzhiyun return status & TUNER_STEREO;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
tuner_islocked(const int status)156*4882a593Smuzhiyun static inline int tuner_islocked(const int status)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun return (status & TUNER_FL);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
tuner_afcstatus(const int status)161*4882a593Smuzhiyun static inline int tuner_afcstatus(const int status)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun return (status & TUNER_AFC) - 2;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun
simple_get_status(struct dvb_frontend * fe,u32 * status)167*4882a593Smuzhiyun static int simple_get_status(struct dvb_frontend *fe, u32 *status)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
170*4882a593Smuzhiyun int tuner_status;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (priv->i2c_props.adap == NULL)
173*4882a593Smuzhiyun return -EINVAL;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun tuner_status = tuner_read_status(fe);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun *status = 0;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if (tuner_islocked(tuner_status))
180*4882a593Smuzhiyun *status = TUNER_STATUS_LOCKED;
181*4882a593Smuzhiyun if (tuner_stereo(priv->type, tuner_status))
182*4882a593Smuzhiyun *status |= TUNER_STATUS_STEREO;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
simple_get_rf_strength(struct dvb_frontend * fe,u16 * strength)189*4882a593Smuzhiyun static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
192*4882a593Smuzhiyun int signal;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (priv->i2c_props.adap == NULL || !priv->radio_mode)
195*4882a593Smuzhiyun return -EINVAL;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun signal = tuner_signal(tuner_read_status(fe));
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun *strength = signal;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun tuner_dbg("Signal strength: %d\n", signal);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return 0;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* ---------------------------------------------------------------------- */
207*4882a593Smuzhiyun
tuner_param_name(enum param_type type)208*4882a593Smuzhiyun static inline char *tuner_param_name(enum param_type type)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun char *name;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun switch (type) {
213*4882a593Smuzhiyun case TUNER_PARAM_TYPE_RADIO:
214*4882a593Smuzhiyun name = "radio";
215*4882a593Smuzhiyun break;
216*4882a593Smuzhiyun case TUNER_PARAM_TYPE_PAL:
217*4882a593Smuzhiyun name = "pal";
218*4882a593Smuzhiyun break;
219*4882a593Smuzhiyun case TUNER_PARAM_TYPE_SECAM:
220*4882a593Smuzhiyun name = "secam";
221*4882a593Smuzhiyun break;
222*4882a593Smuzhiyun case TUNER_PARAM_TYPE_NTSC:
223*4882a593Smuzhiyun name = "ntsc";
224*4882a593Smuzhiyun break;
225*4882a593Smuzhiyun case TUNER_PARAM_TYPE_DIGITAL:
226*4882a593Smuzhiyun name = "digital";
227*4882a593Smuzhiyun break;
228*4882a593Smuzhiyun default:
229*4882a593Smuzhiyun name = "unknown";
230*4882a593Smuzhiyun break;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun return name;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
simple_tuner_params(struct dvb_frontend * fe,enum param_type desired_type)235*4882a593Smuzhiyun static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
236*4882a593Smuzhiyun enum param_type desired_type)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
239*4882a593Smuzhiyun struct tunertype *tun = priv->tun;
240*4882a593Smuzhiyun int i;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun for (i = 0; i < tun->count; i++)
243*4882a593Smuzhiyun if (desired_type == tun->params[i].type)
244*4882a593Smuzhiyun break;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* use default tuner params if desired_type not available */
247*4882a593Smuzhiyun if (i == tun->count) {
248*4882a593Smuzhiyun tuner_dbg("desired params (%s) undefined for tuner %d\n",
249*4882a593Smuzhiyun tuner_param_name(desired_type), priv->type);
250*4882a593Smuzhiyun i = 0;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun tuner_dbg("using tuner params #%d (%s)\n", i,
254*4882a593Smuzhiyun tuner_param_name(tun->params[i].type));
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun return &tun->params[i];
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
simple_config_lookup(struct dvb_frontend * fe,struct tuner_params * t_params,unsigned * frequency,u8 * config,u8 * cb)259*4882a593Smuzhiyun static int simple_config_lookup(struct dvb_frontend *fe,
260*4882a593Smuzhiyun struct tuner_params *t_params,
261*4882a593Smuzhiyun unsigned *frequency, u8 *config, u8 *cb)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
264*4882a593Smuzhiyun int i;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun for (i = 0; i < t_params->count; i++) {
267*4882a593Smuzhiyun if (*frequency > t_params->ranges[i].limit)
268*4882a593Smuzhiyun continue;
269*4882a593Smuzhiyun break;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun if (i == t_params->count) {
272*4882a593Smuzhiyun tuner_dbg("frequency out of range (%d > %d)\n",
273*4882a593Smuzhiyun *frequency, t_params->ranges[i - 1].limit);
274*4882a593Smuzhiyun *frequency = t_params->ranges[--i].limit;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun *config = t_params->ranges[i].config;
277*4882a593Smuzhiyun *cb = t_params->ranges[i].cb;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun tuner_dbg("freq = %d.%02d (%d), range = %d, config = 0x%02x, cb = 0x%02x\n",
280*4882a593Smuzhiyun *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
281*4882a593Smuzhiyun i, *config, *cb);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun return i;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* ---------------------------------------------------------------------- */
287*4882a593Smuzhiyun
simple_set_rf_input(struct dvb_frontend * fe,u8 * config,u8 * cb,unsigned int rf)288*4882a593Smuzhiyun static void simple_set_rf_input(struct dvb_frontend *fe,
289*4882a593Smuzhiyun u8 *config, u8 *cb, unsigned int rf)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun switch (priv->type) {
294*4882a593Smuzhiyun case TUNER_PHILIPS_TUV1236D:
295*4882a593Smuzhiyun switch (rf) {
296*4882a593Smuzhiyun case 1:
297*4882a593Smuzhiyun *cb |= 0x08;
298*4882a593Smuzhiyun break;
299*4882a593Smuzhiyun default:
300*4882a593Smuzhiyun *cb &= ~0x08;
301*4882a593Smuzhiyun break;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun case TUNER_PHILIPS_FCV1236D:
305*4882a593Smuzhiyun switch (rf) {
306*4882a593Smuzhiyun case 1:
307*4882a593Smuzhiyun *cb |= 0x01;
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun default:
310*4882a593Smuzhiyun *cb &= ~0x01;
311*4882a593Smuzhiyun break;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun break;
314*4882a593Smuzhiyun default:
315*4882a593Smuzhiyun break;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
simple_std_setup(struct dvb_frontend * fe,struct analog_parameters * params,u8 * config,u8 * cb)319*4882a593Smuzhiyun static int simple_std_setup(struct dvb_frontend *fe,
320*4882a593Smuzhiyun struct analog_parameters *params,
321*4882a593Smuzhiyun u8 *config, u8 *cb)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
324*4882a593Smuzhiyun int rc;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /* tv norm specific stuff for multi-norm tuners */
327*4882a593Smuzhiyun switch (priv->type) {
328*4882a593Smuzhiyun case TUNER_PHILIPS_SECAM: /* FI1216MF */
329*4882a593Smuzhiyun /* 0x01 -> ??? no change ??? */
330*4882a593Smuzhiyun /* 0x02 -> PAL BDGHI / SECAM L */
331*4882a593Smuzhiyun /* 0x04 -> ??? PAL others / SECAM others ??? */
332*4882a593Smuzhiyun *cb &= ~0x03;
333*4882a593Smuzhiyun if (params->std & V4L2_STD_SECAM_L)
334*4882a593Smuzhiyun /* also valid for V4L2_STD_SECAM */
335*4882a593Smuzhiyun *cb |= PHILIPS_MF_SET_STD_L;
336*4882a593Smuzhiyun else if (params->std & V4L2_STD_SECAM_LC)
337*4882a593Smuzhiyun *cb |= PHILIPS_MF_SET_STD_LC;
338*4882a593Smuzhiyun else /* V4L2_STD_B|V4L2_STD_GH */
339*4882a593Smuzhiyun *cb |= PHILIPS_MF_SET_STD_BG;
340*4882a593Smuzhiyun break;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun case TUNER_TEMIC_4046FM5:
343*4882a593Smuzhiyun *cb &= ~0x0f;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (params->std & V4L2_STD_PAL_BG) {
346*4882a593Smuzhiyun *cb |= TEMIC_SET_PAL_BG;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun } else if (params->std & V4L2_STD_PAL_I) {
349*4882a593Smuzhiyun *cb |= TEMIC_SET_PAL_I;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun } else if (params->std & V4L2_STD_PAL_DK) {
352*4882a593Smuzhiyun *cb |= TEMIC_SET_PAL_DK;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun } else if (params->std & V4L2_STD_SECAM_L) {
355*4882a593Smuzhiyun *cb |= TEMIC_SET_PAL_L;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun case TUNER_PHILIPS_FQ1216ME:
361*4882a593Smuzhiyun *cb &= ~0x0f;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
364*4882a593Smuzhiyun *cb |= PHILIPS_SET_PAL_BGDK;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun } else if (params->std & V4L2_STD_PAL_I) {
367*4882a593Smuzhiyun *cb |= PHILIPS_SET_PAL_I;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun } else if (params->std & V4L2_STD_SECAM_L) {
370*4882a593Smuzhiyun *cb |= PHILIPS_SET_PAL_L;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun break;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun case TUNER_PHILIPS_FCV1236D:
376*4882a593Smuzhiyun /* 0x00 -> ATSC antenna input 1 */
377*4882a593Smuzhiyun /* 0x01 -> ATSC antenna input 2 */
378*4882a593Smuzhiyun /* 0x02 -> NTSC antenna input 1 */
379*4882a593Smuzhiyun /* 0x03 -> NTSC antenna input 2 */
380*4882a593Smuzhiyun *cb &= ~0x03;
381*4882a593Smuzhiyun if (!(params->std & V4L2_STD_ATSC))
382*4882a593Smuzhiyun *cb |= 2;
383*4882a593Smuzhiyun break;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun case TUNER_MICROTUNE_4042FI5:
386*4882a593Smuzhiyun /* Set the charge pump for fast tuning */
387*4882a593Smuzhiyun *config |= TUNER_CHARGE_PUMP;
388*4882a593Smuzhiyun break;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun case TUNER_PHILIPS_TUV1236D:
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun struct tuner_i2c_props i2c = priv->i2c_props;
393*4882a593Smuzhiyun /* 0x40 -> ATSC antenna input 1 */
394*4882a593Smuzhiyun /* 0x48 -> ATSC antenna input 2 */
395*4882a593Smuzhiyun /* 0x00 -> NTSC antenna input 1 */
396*4882a593Smuzhiyun /* 0x08 -> NTSC antenna input 2 */
397*4882a593Smuzhiyun u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
398*4882a593Smuzhiyun *cb &= ~0x40;
399*4882a593Smuzhiyun if (params->std & V4L2_STD_ATSC) {
400*4882a593Smuzhiyun *cb |= 0x40;
401*4882a593Smuzhiyun buffer[1] = 0x04;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun /* set to the correct mode (analog or digital) */
404*4882a593Smuzhiyun i2c.addr = 0x0a;
405*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
406*4882a593Smuzhiyun if (2 != rc)
407*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 2)\n",
408*4882a593Smuzhiyun rc);
409*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
410*4882a593Smuzhiyun if (2 != rc)
411*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 2)\n",
412*4882a593Smuzhiyun rc);
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun if (atv_input[priv->nr])
417*4882a593Smuzhiyun simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun return 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
simple_set_aux_byte(struct dvb_frontend * fe,u8 config,u8 aux)422*4882a593Smuzhiyun static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
425*4882a593Smuzhiyun int rc;
426*4882a593Smuzhiyun u8 buffer[2];
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun buffer[0] = (config & ~0x38) | 0x18;
429*4882a593Smuzhiyun buffer[1] = aux;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
434*4882a593Smuzhiyun if (2 != rc)
435*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun return rc == 2 ? 0 : rc;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
simple_post_tune(struct dvb_frontend * fe,u8 * buffer,u16 div,u8 config,u8 cb)440*4882a593Smuzhiyun static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
441*4882a593Smuzhiyun u16 div, u8 config, u8 cb)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
444*4882a593Smuzhiyun int rc;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun switch (priv->type) {
447*4882a593Smuzhiyun case TUNER_LG_TDVS_H06XF:
448*4882a593Smuzhiyun simple_set_aux_byte(fe, config, 0x20);
449*4882a593Smuzhiyun break;
450*4882a593Smuzhiyun case TUNER_PHILIPS_FQ1216LME_MK3:
451*4882a593Smuzhiyun simple_set_aux_byte(fe, config, 0x60); /* External AGC */
452*4882a593Smuzhiyun break;
453*4882a593Smuzhiyun case TUNER_MICROTUNE_4042FI5:
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun /* FIXME - this may also work for other tuners */
456*4882a593Smuzhiyun unsigned long timeout = jiffies + msecs_to_jiffies(1);
457*4882a593Smuzhiyun u8 status_byte = 0;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* Wait until the PLL locks */
460*4882a593Smuzhiyun for (;;) {
461*4882a593Smuzhiyun if (time_after(jiffies, timeout))
462*4882a593Smuzhiyun return 0;
463*4882a593Smuzhiyun rc = tuner_i2c_xfer_recv(&priv->i2c_props,
464*4882a593Smuzhiyun &status_byte, 1);
465*4882a593Smuzhiyun if (1 != rc) {
466*4882a593Smuzhiyun tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",
467*4882a593Smuzhiyun rc);
468*4882a593Smuzhiyun break;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun if (status_byte & TUNER_PLL_LOCKED)
471*4882a593Smuzhiyun break;
472*4882a593Smuzhiyun udelay(10);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /* Set the charge pump for optimized phase noise figure */
476*4882a593Smuzhiyun config &= ~TUNER_CHARGE_PUMP;
477*4882a593Smuzhiyun buffer[0] = (div>>8) & 0x7f;
478*4882a593Smuzhiyun buffer[1] = div & 0xff;
479*4882a593Smuzhiyun buffer[2] = config;
480*4882a593Smuzhiyun buffer[3] = cb;
481*4882a593Smuzhiyun tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
482*4882a593Smuzhiyun buffer[0], buffer[1], buffer[2], buffer[3]);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
485*4882a593Smuzhiyun if (4 != rc)
486*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 4)\n",
487*4882a593Smuzhiyun rc);
488*4882a593Smuzhiyun break;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
simple_radio_bandswitch(struct dvb_frontend * fe,u8 * buffer)495*4882a593Smuzhiyun static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun switch (priv->type) {
500*4882a593Smuzhiyun case TUNER_TENA_9533_DI:
501*4882a593Smuzhiyun case TUNER_YMEC_TVF_5533MF:
502*4882a593Smuzhiyun tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
503*4882a593Smuzhiyun return -EINVAL;
504*4882a593Smuzhiyun case TUNER_PHILIPS_FM1216ME_MK3:
505*4882a593Smuzhiyun case TUNER_PHILIPS_FM1236_MK3:
506*4882a593Smuzhiyun case TUNER_PHILIPS_FMD1216ME_MK3:
507*4882a593Smuzhiyun case TUNER_PHILIPS_FMD1216MEX_MK3:
508*4882a593Smuzhiyun case TUNER_LG_NTSC_TAPE:
509*4882a593Smuzhiyun case TUNER_PHILIPS_FM1256_IH3:
510*4882a593Smuzhiyun case TUNER_TCL_MF02GIP_5N:
511*4882a593Smuzhiyun buffer[3] = 0x19;
512*4882a593Smuzhiyun break;
513*4882a593Smuzhiyun case TUNER_PHILIPS_FM1216MK5:
514*4882a593Smuzhiyun buffer[2] = 0x88;
515*4882a593Smuzhiyun buffer[3] = 0x09;
516*4882a593Smuzhiyun break;
517*4882a593Smuzhiyun case TUNER_TNF_5335MF:
518*4882a593Smuzhiyun buffer[3] = 0x11;
519*4882a593Smuzhiyun break;
520*4882a593Smuzhiyun case TUNER_LG_PAL_FM:
521*4882a593Smuzhiyun buffer[3] = 0xa5;
522*4882a593Smuzhiyun break;
523*4882a593Smuzhiyun case TUNER_THOMSON_DTT761X:
524*4882a593Smuzhiyun buffer[3] = 0x39;
525*4882a593Smuzhiyun break;
526*4882a593Smuzhiyun case TUNER_PHILIPS_FQ1216LME_MK3:
527*4882a593Smuzhiyun case TUNER_PHILIPS_FQ1236_MK5:
528*4882a593Smuzhiyun tuner_err("This tuner doesn't have FM\n");
529*4882a593Smuzhiyun /* Set the low band for sanity, since it covers 88-108 MHz */
530*4882a593Smuzhiyun buffer[3] = 0x01;
531*4882a593Smuzhiyun break;
532*4882a593Smuzhiyun case TUNER_MICROTUNE_4049FM5:
533*4882a593Smuzhiyun default:
534*4882a593Smuzhiyun buffer[3] = 0xa4;
535*4882a593Smuzhiyun break;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return 0;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /* ---------------------------------------------------------------------- */
542*4882a593Smuzhiyun
simple_set_tv_freq(struct dvb_frontend * fe,struct analog_parameters * params)543*4882a593Smuzhiyun static int simple_set_tv_freq(struct dvb_frontend *fe,
544*4882a593Smuzhiyun struct analog_parameters *params)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
547*4882a593Smuzhiyun u8 config, cb;
548*4882a593Smuzhiyun u16 div;
549*4882a593Smuzhiyun u8 buffer[4];
550*4882a593Smuzhiyun int rc, IFPCoff, i;
551*4882a593Smuzhiyun enum param_type desired_type;
552*4882a593Smuzhiyun struct tuner_params *t_params;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /* IFPCoff = Video Intermediate Frequency - Vif:
555*4882a593Smuzhiyun 940 =16*58.75 NTSC/J (Japan)
556*4882a593Smuzhiyun 732 =16*45.75 M/N STD
557*4882a593Smuzhiyun 704 =16*44 ATSC (at DVB code)
558*4882a593Smuzhiyun 632 =16*39.50 I U.K.
559*4882a593Smuzhiyun 622.4=16*38.90 B/G D/K I, L STD
560*4882a593Smuzhiyun 592 =16*37.00 D China
561*4882a593Smuzhiyun 590 =16.36.875 B Australia
562*4882a593Smuzhiyun 543.2=16*33.95 L' STD
563*4882a593Smuzhiyun 171.2=16*10.70 FM Radio (at set_radio_freq)
564*4882a593Smuzhiyun */
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun if (params->std == V4L2_STD_NTSC_M_JP) {
567*4882a593Smuzhiyun IFPCoff = 940;
568*4882a593Smuzhiyun desired_type = TUNER_PARAM_TYPE_NTSC;
569*4882a593Smuzhiyun } else if ((params->std & V4L2_STD_MN) &&
570*4882a593Smuzhiyun !(params->std & ~V4L2_STD_MN)) {
571*4882a593Smuzhiyun IFPCoff = 732;
572*4882a593Smuzhiyun desired_type = TUNER_PARAM_TYPE_NTSC;
573*4882a593Smuzhiyun } else if (params->std == V4L2_STD_SECAM_LC) {
574*4882a593Smuzhiyun IFPCoff = 543;
575*4882a593Smuzhiyun desired_type = TUNER_PARAM_TYPE_SECAM;
576*4882a593Smuzhiyun } else {
577*4882a593Smuzhiyun IFPCoff = 623;
578*4882a593Smuzhiyun desired_type = TUNER_PARAM_TYPE_PAL;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun t_params = simple_tuner_params(fe, desired_type);
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun i = simple_config_lookup(fe, t_params, ¶ms->frequency,
584*4882a593Smuzhiyun &config, &cb);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun div = params->frequency + IFPCoff + offset;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
589*4882a593Smuzhiyun params->frequency / 16, params->frequency % 16 * 100 / 16,
590*4882a593Smuzhiyun IFPCoff / 16, IFPCoff % 16 * 100 / 16,
591*4882a593Smuzhiyun offset / 16, offset % 16 * 100 / 16, div);
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /* tv norm specific stuff for multi-norm tuners */
594*4882a593Smuzhiyun simple_std_setup(fe, params, &config, &cb);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
597*4882a593Smuzhiyun buffer[0] = config;
598*4882a593Smuzhiyun buffer[1] = cb;
599*4882a593Smuzhiyun buffer[2] = (div>>8) & 0x7f;
600*4882a593Smuzhiyun buffer[3] = div & 0xff;
601*4882a593Smuzhiyun } else {
602*4882a593Smuzhiyun buffer[0] = (div>>8) & 0x7f;
603*4882a593Smuzhiyun buffer[1] = div & 0xff;
604*4882a593Smuzhiyun buffer[2] = config;
605*4882a593Smuzhiyun buffer[3] = cb;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun priv->last_div = div;
608*4882a593Smuzhiyun if (t_params->has_tda9887) {
609*4882a593Smuzhiyun struct v4l2_priv_tun_config tda9887_cfg;
610*4882a593Smuzhiyun int tda_config = 0;
611*4882a593Smuzhiyun int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
612*4882a593Smuzhiyun V4L2_STD_SECAM_LC)) &&
613*4882a593Smuzhiyun !(params->std & ~(V4L2_STD_SECAM_L |
614*4882a593Smuzhiyun V4L2_STD_SECAM_LC));
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun tda9887_cfg.tuner = TUNER_TDA9887;
617*4882a593Smuzhiyun tda9887_cfg.priv = &tda_config;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (params->std == V4L2_STD_SECAM_LC) {
620*4882a593Smuzhiyun if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
621*4882a593Smuzhiyun tda_config |= TDA9887_PORT1_ACTIVE;
622*4882a593Smuzhiyun if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
623*4882a593Smuzhiyun tda_config |= TDA9887_PORT2_ACTIVE;
624*4882a593Smuzhiyun } else {
625*4882a593Smuzhiyun if (t_params->port1_active)
626*4882a593Smuzhiyun tda_config |= TDA9887_PORT1_ACTIVE;
627*4882a593Smuzhiyun if (t_params->port2_active)
628*4882a593Smuzhiyun tda_config |= TDA9887_PORT2_ACTIVE;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun if (t_params->intercarrier_mode)
631*4882a593Smuzhiyun tda_config |= TDA9887_INTERCARRIER;
632*4882a593Smuzhiyun if (is_secam_l) {
633*4882a593Smuzhiyun if (i == 0 && t_params->default_top_secam_low)
634*4882a593Smuzhiyun tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
635*4882a593Smuzhiyun else if (i == 1 && t_params->default_top_secam_mid)
636*4882a593Smuzhiyun tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
637*4882a593Smuzhiyun else if (t_params->default_top_secam_high)
638*4882a593Smuzhiyun tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
639*4882a593Smuzhiyun } else {
640*4882a593Smuzhiyun if (i == 0 && t_params->default_top_low)
641*4882a593Smuzhiyun tda_config |= TDA9887_TOP(t_params->default_top_low);
642*4882a593Smuzhiyun else if (i == 1 && t_params->default_top_mid)
643*4882a593Smuzhiyun tda_config |= TDA9887_TOP(t_params->default_top_mid);
644*4882a593Smuzhiyun else if (t_params->default_top_high)
645*4882a593Smuzhiyun tda_config |= TDA9887_TOP(t_params->default_top_high);
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun if (t_params->default_pll_gating_18)
648*4882a593Smuzhiyun tda_config |= TDA9887_GATING_18;
649*4882a593Smuzhiyun i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
650*4882a593Smuzhiyun &tda9887_cfg);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
653*4882a593Smuzhiyun buffer[0], buffer[1], buffer[2], buffer[3]);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
656*4882a593Smuzhiyun if (4 != rc)
657*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun simple_post_tune(fe, &buffer[0], div, config, cb);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
simple_set_radio_freq(struct dvb_frontend * fe,struct analog_parameters * params)664*4882a593Smuzhiyun static int simple_set_radio_freq(struct dvb_frontend *fe,
665*4882a593Smuzhiyun struct analog_parameters *params)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun struct tunertype *tun;
668*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
669*4882a593Smuzhiyun u8 buffer[4];
670*4882a593Smuzhiyun u16 div;
671*4882a593Smuzhiyun int rc, j;
672*4882a593Smuzhiyun struct tuner_params *t_params;
673*4882a593Smuzhiyun unsigned int freq = params->frequency;
674*4882a593Smuzhiyun bool mono = params->audmode == V4L2_TUNER_MODE_MONO;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun tun = priv->tun;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun for (j = tun->count-1; j > 0; j--)
679*4882a593Smuzhiyun if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
680*4882a593Smuzhiyun break;
681*4882a593Smuzhiyun /* default t_params (j=0) will be used if desired type wasn't found */
682*4882a593Smuzhiyun t_params = &tun->params[j];
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun /* Select Radio 1st IF used */
685*4882a593Smuzhiyun switch (t_params->radio_if) {
686*4882a593Smuzhiyun case 0: /* 10.7 MHz */
687*4882a593Smuzhiyun freq += (unsigned int)(10.7*16000);
688*4882a593Smuzhiyun break;
689*4882a593Smuzhiyun case 1: /* 33.3 MHz */
690*4882a593Smuzhiyun freq += (unsigned int)(33.3*16000);
691*4882a593Smuzhiyun break;
692*4882a593Smuzhiyun case 2: /* 41.3 MHz */
693*4882a593Smuzhiyun freq += (unsigned int)(41.3*16000);
694*4882a593Smuzhiyun break;
695*4882a593Smuzhiyun default:
696*4882a593Smuzhiyun tuner_warn("Unsupported radio_if value %d\n",
697*4882a593Smuzhiyun t_params->radio_if);
698*4882a593Smuzhiyun return 0;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
702*4882a593Smuzhiyun TUNER_RATIO_SELECT_50; /* 50 kHz step */
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun /* Bandswitch byte */
705*4882a593Smuzhiyun if (simple_radio_bandswitch(fe, &buffer[0]))
706*4882a593Smuzhiyun return 0;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
709*4882a593Smuzhiyun freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
710*4882a593Smuzhiyun freq * (1/800) */
711*4882a593Smuzhiyun div = (freq + 400) / 800;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
714*4882a593Smuzhiyun buffer[0] = buffer[2];
715*4882a593Smuzhiyun buffer[1] = buffer[3];
716*4882a593Smuzhiyun buffer[2] = (div>>8) & 0x7f;
717*4882a593Smuzhiyun buffer[3] = div & 0xff;
718*4882a593Smuzhiyun } else {
719*4882a593Smuzhiyun buffer[0] = (div>>8) & 0x7f;
720*4882a593Smuzhiyun buffer[1] = div & 0xff;
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
724*4882a593Smuzhiyun buffer[0], buffer[1], buffer[2], buffer[3]);
725*4882a593Smuzhiyun priv->last_div = div;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun if (t_params->has_tda9887) {
728*4882a593Smuzhiyun int config = 0;
729*4882a593Smuzhiyun struct v4l2_priv_tun_config tda9887_cfg;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun tda9887_cfg.tuner = TUNER_TDA9887;
732*4882a593Smuzhiyun tda9887_cfg.priv = &config;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun if (t_params->port1_active &&
735*4882a593Smuzhiyun !t_params->port1_fm_high_sensitivity)
736*4882a593Smuzhiyun config |= TDA9887_PORT1_ACTIVE;
737*4882a593Smuzhiyun if (t_params->port2_active &&
738*4882a593Smuzhiyun !t_params->port2_fm_high_sensitivity)
739*4882a593Smuzhiyun config |= TDA9887_PORT2_ACTIVE;
740*4882a593Smuzhiyun if (t_params->intercarrier_mode)
741*4882a593Smuzhiyun config |= TDA9887_INTERCARRIER;
742*4882a593Smuzhiyun if (t_params->port1_set_for_fm_mono && mono)
743*4882a593Smuzhiyun config &= ~TDA9887_PORT1_ACTIVE;
744*4882a593Smuzhiyun if (t_params->fm_gain_normal)
745*4882a593Smuzhiyun config |= TDA9887_GAIN_NORMAL;
746*4882a593Smuzhiyun if (t_params->radio_if == 2)
747*4882a593Smuzhiyun config |= TDA9887_RIF_41_3;
748*4882a593Smuzhiyun i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
749*4882a593Smuzhiyun &tda9887_cfg);
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
752*4882a593Smuzhiyun if (4 != rc)
753*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun /* Write AUX byte */
756*4882a593Smuzhiyun switch (priv->type) {
757*4882a593Smuzhiyun case TUNER_PHILIPS_FM1216ME_MK3:
758*4882a593Smuzhiyun buffer[2] = 0x98;
759*4882a593Smuzhiyun buffer[3] = 0x20; /* set TOP AGC */
760*4882a593Smuzhiyun rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
761*4882a593Smuzhiyun if (4 != rc)
762*4882a593Smuzhiyun tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
763*4882a593Smuzhiyun break;
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun return 0;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun
simple_set_params(struct dvb_frontend * fe,struct analog_parameters * params)769*4882a593Smuzhiyun static int simple_set_params(struct dvb_frontend *fe,
770*4882a593Smuzhiyun struct analog_parameters *params)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
773*4882a593Smuzhiyun int ret = -EINVAL;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (priv->i2c_props.adap == NULL)
776*4882a593Smuzhiyun return -EINVAL;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun switch (params->mode) {
779*4882a593Smuzhiyun case V4L2_TUNER_RADIO:
780*4882a593Smuzhiyun priv->radio_mode = true;
781*4882a593Smuzhiyun ret = simple_set_radio_freq(fe, params);
782*4882a593Smuzhiyun priv->frequency = params->frequency * 125 / 2;
783*4882a593Smuzhiyun break;
784*4882a593Smuzhiyun case V4L2_TUNER_ANALOG_TV:
785*4882a593Smuzhiyun case V4L2_TUNER_DIGITAL_TV:
786*4882a593Smuzhiyun priv->radio_mode = false;
787*4882a593Smuzhiyun ret = simple_set_tv_freq(fe, params);
788*4882a593Smuzhiyun priv->frequency = params->frequency * 62500;
789*4882a593Smuzhiyun break;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun priv->bandwidth = 0;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun return ret;
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun
simple_set_dvb(struct dvb_frontend * fe,u8 * buf,const u32 delsys,const u32 frequency,const u32 bandwidth)796*4882a593Smuzhiyun static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
797*4882a593Smuzhiyun const u32 delsys,
798*4882a593Smuzhiyun const u32 frequency,
799*4882a593Smuzhiyun const u32 bandwidth)
800*4882a593Smuzhiyun {
801*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun switch (priv->type) {
804*4882a593Smuzhiyun case TUNER_PHILIPS_FMD1216ME_MK3:
805*4882a593Smuzhiyun case TUNER_PHILIPS_FMD1216MEX_MK3:
806*4882a593Smuzhiyun if (bandwidth == 8000000 &&
807*4882a593Smuzhiyun frequency >= 158870000)
808*4882a593Smuzhiyun buf[3] |= 0x08;
809*4882a593Smuzhiyun break;
810*4882a593Smuzhiyun case TUNER_PHILIPS_TD1316:
811*4882a593Smuzhiyun /* determine band */
812*4882a593Smuzhiyun buf[3] |= (frequency < 161000000) ? 1 :
813*4882a593Smuzhiyun (frequency < 444000000) ? 2 : 4;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun /* setup PLL filter */
816*4882a593Smuzhiyun if (bandwidth == 8000000)
817*4882a593Smuzhiyun buf[3] |= 1 << 3;
818*4882a593Smuzhiyun break;
819*4882a593Smuzhiyun case TUNER_PHILIPS_TUV1236D:
820*4882a593Smuzhiyun case TUNER_PHILIPS_FCV1236D:
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun unsigned int new_rf;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun if (dtv_input[priv->nr])
825*4882a593Smuzhiyun new_rf = dtv_input[priv->nr];
826*4882a593Smuzhiyun else
827*4882a593Smuzhiyun switch (delsys) {
828*4882a593Smuzhiyun case SYS_DVBC_ANNEX_B:
829*4882a593Smuzhiyun new_rf = 1;
830*4882a593Smuzhiyun break;
831*4882a593Smuzhiyun case SYS_ATSC:
832*4882a593Smuzhiyun default:
833*4882a593Smuzhiyun new_rf = 0;
834*4882a593Smuzhiyun break;
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
837*4882a593Smuzhiyun break;
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun default:
840*4882a593Smuzhiyun break;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
simple_dvb_configure(struct dvb_frontend * fe,u8 * buf,const u32 delsys,const u32 freq,const u32 bw)844*4882a593Smuzhiyun static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
845*4882a593Smuzhiyun const u32 delsys,
846*4882a593Smuzhiyun const u32 freq,
847*4882a593Smuzhiyun const u32 bw)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun /* This function returns the tuned frequency on success, 0 on error */
850*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
851*4882a593Smuzhiyun struct tunertype *tun = priv->tun;
852*4882a593Smuzhiyun struct tuner_params *t_params;
853*4882a593Smuzhiyun u8 config, cb;
854*4882a593Smuzhiyun u32 div;
855*4882a593Smuzhiyun int ret;
856*4882a593Smuzhiyun u32 frequency = freq / 62500;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun if (!tun->stepsize) {
859*4882a593Smuzhiyun /* tuner-core was loaded before the digital tuner was
860*4882a593Smuzhiyun * configured and somehow picked the wrong tuner type */
861*4882a593Smuzhiyun tuner_err("attempt to treat tuner %d (%s) as digital tuner without stepsize defined.\n",
862*4882a593Smuzhiyun priv->type, priv->tun->name);
863*4882a593Smuzhiyun return 0; /* failure */
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
867*4882a593Smuzhiyun ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
868*4882a593Smuzhiyun if (ret < 0)
869*4882a593Smuzhiyun return 0; /* failure */
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun div = ((frequency + t_params->iffreq) * 62500 + offset +
872*4882a593Smuzhiyun tun->stepsize/2) / tun->stepsize;
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun buf[0] = div >> 8;
875*4882a593Smuzhiyun buf[1] = div & 0xff;
876*4882a593Smuzhiyun buf[2] = config;
877*4882a593Smuzhiyun buf[3] = cb;
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun simple_set_dvb(fe, buf, delsys, freq, bw);
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
882*4882a593Smuzhiyun tun->name, div, buf[0], buf[1], buf[2], buf[3]);
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun /* calculate the frequency we set it to */
885*4882a593Smuzhiyun return (div * tun->stepsize) - t_params->iffreq;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun
simple_dvb_calc_regs(struct dvb_frontend * fe,u8 * buf,int buf_len)888*4882a593Smuzhiyun static int simple_dvb_calc_regs(struct dvb_frontend *fe,
889*4882a593Smuzhiyun u8 *buf, int buf_len)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun struct dtv_frontend_properties *c = &fe->dtv_property_cache;
892*4882a593Smuzhiyun u32 delsys = c->delivery_system;
893*4882a593Smuzhiyun u32 bw = c->bandwidth_hz;
894*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
895*4882a593Smuzhiyun u32 frequency;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun if (buf_len < 5)
898*4882a593Smuzhiyun return -EINVAL;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
901*4882a593Smuzhiyun if (frequency == 0)
902*4882a593Smuzhiyun return -EINVAL;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun buf[0] = priv->i2c_props.addr;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun priv->frequency = frequency;
907*4882a593Smuzhiyun priv->bandwidth = c->bandwidth_hz;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun return 5;
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun
simple_dvb_set_params(struct dvb_frontend * fe)912*4882a593Smuzhiyun static int simple_dvb_set_params(struct dvb_frontend *fe)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun struct dtv_frontend_properties *c = &fe->dtv_property_cache;
915*4882a593Smuzhiyun u32 delsys = c->delivery_system;
916*4882a593Smuzhiyun u32 bw = c->bandwidth_hz;
917*4882a593Smuzhiyun u32 freq = c->frequency;
918*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
919*4882a593Smuzhiyun u32 frequency;
920*4882a593Smuzhiyun u32 prev_freq, prev_bw;
921*4882a593Smuzhiyun int ret;
922*4882a593Smuzhiyun u8 buf[5];
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun if (priv->i2c_props.adap == NULL)
925*4882a593Smuzhiyun return -EINVAL;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun prev_freq = priv->frequency;
928*4882a593Smuzhiyun prev_bw = priv->bandwidth;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
931*4882a593Smuzhiyun if (frequency == 0)
932*4882a593Smuzhiyun return -EINVAL;
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun buf[0] = priv->i2c_props.addr;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun priv->frequency = frequency;
937*4882a593Smuzhiyun priv->bandwidth = bw;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun /* put analog demod in standby when tuning digital */
940*4882a593Smuzhiyun if (fe->ops.analog_ops.standby)
941*4882a593Smuzhiyun fe->ops.analog_ops.standby(fe);
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl)
944*4882a593Smuzhiyun fe->ops.i2c_gate_ctrl(fe, 1);
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun /* buf[0] contains the i2c address, but *
947*4882a593Smuzhiyun * we already have it in i2c_props.addr */
948*4882a593Smuzhiyun ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
949*4882a593Smuzhiyun if (ret != 4)
950*4882a593Smuzhiyun goto fail;
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun return 0;
953*4882a593Smuzhiyun fail:
954*4882a593Smuzhiyun /* calc_regs sets frequency and bandwidth. if we failed, unset them */
955*4882a593Smuzhiyun priv->frequency = prev_freq;
956*4882a593Smuzhiyun priv->bandwidth = prev_bw;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun return ret;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
simple_init(struct dvb_frontend * fe)961*4882a593Smuzhiyun static int simple_init(struct dvb_frontend *fe)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun if (priv->i2c_props.adap == NULL)
966*4882a593Smuzhiyun return -EINVAL;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun if (priv->tun->initdata) {
969*4882a593Smuzhiyun int ret;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl)
972*4882a593Smuzhiyun fe->ops.i2c_gate_ctrl(fe, 1);
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun ret = tuner_i2c_xfer_send(&priv->i2c_props,
975*4882a593Smuzhiyun priv->tun->initdata + 1,
976*4882a593Smuzhiyun priv->tun->initdata[0]);
977*4882a593Smuzhiyun if (ret != priv->tun->initdata[0])
978*4882a593Smuzhiyun return ret;
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun return 0;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
simple_sleep(struct dvb_frontend * fe)984*4882a593Smuzhiyun static int simple_sleep(struct dvb_frontend *fe)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun if (priv->i2c_props.adap == NULL)
989*4882a593Smuzhiyun return -EINVAL;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun if (priv->tun->sleepdata) {
992*4882a593Smuzhiyun int ret;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl)
995*4882a593Smuzhiyun fe->ops.i2c_gate_ctrl(fe, 1);
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun ret = tuner_i2c_xfer_send(&priv->i2c_props,
998*4882a593Smuzhiyun priv->tun->sleepdata + 1,
999*4882a593Smuzhiyun priv->tun->sleepdata[0]);
1000*4882a593Smuzhiyun if (ret != priv->tun->sleepdata[0])
1001*4882a593Smuzhiyun return ret;
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun return 0;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun
simple_release(struct dvb_frontend * fe)1007*4882a593Smuzhiyun static void simple_release(struct dvb_frontend *fe)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun mutex_lock(&tuner_simple_list_mutex);
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun if (priv)
1014*4882a593Smuzhiyun hybrid_tuner_release_state(priv);
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun mutex_unlock(&tuner_simple_list_mutex);
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun fe->tuner_priv = NULL;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun
simple_get_frequency(struct dvb_frontend * fe,u32 * frequency)1021*4882a593Smuzhiyun static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
1024*4882a593Smuzhiyun *frequency = priv->frequency;
1025*4882a593Smuzhiyun return 0;
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun
simple_get_bandwidth(struct dvb_frontend * fe,u32 * bandwidth)1028*4882a593Smuzhiyun static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun struct tuner_simple_priv *priv = fe->tuner_priv;
1031*4882a593Smuzhiyun *bandwidth = priv->bandwidth;
1032*4882a593Smuzhiyun return 0;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun static const struct dvb_tuner_ops simple_tuner_ops = {
1036*4882a593Smuzhiyun .init = simple_init,
1037*4882a593Smuzhiyun .sleep = simple_sleep,
1038*4882a593Smuzhiyun .set_analog_params = simple_set_params,
1039*4882a593Smuzhiyun .set_params = simple_dvb_set_params,
1040*4882a593Smuzhiyun .calc_regs = simple_dvb_calc_regs,
1041*4882a593Smuzhiyun .release = simple_release,
1042*4882a593Smuzhiyun .get_frequency = simple_get_frequency,
1043*4882a593Smuzhiyun .get_bandwidth = simple_get_bandwidth,
1044*4882a593Smuzhiyun .get_status = simple_get_status,
1045*4882a593Smuzhiyun .get_rf_strength = simple_get_rf_strength,
1046*4882a593Smuzhiyun };
1047*4882a593Smuzhiyun
simple_tuner_attach(struct dvb_frontend * fe,struct i2c_adapter * i2c_adap,u8 i2c_addr,unsigned int type)1048*4882a593Smuzhiyun struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
1049*4882a593Smuzhiyun struct i2c_adapter *i2c_adap,
1050*4882a593Smuzhiyun u8 i2c_addr,
1051*4882a593Smuzhiyun unsigned int type)
1052*4882a593Smuzhiyun {
1053*4882a593Smuzhiyun struct tuner_simple_priv *priv = NULL;
1054*4882a593Smuzhiyun int instance;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun if (type >= tuner_count) {
1057*4882a593Smuzhiyun printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
1058*4882a593Smuzhiyun __func__, type, tuner_count-1);
1059*4882a593Smuzhiyun return NULL;
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun /* If i2c_adap is set, check that the tuner is at the correct address.
1063*4882a593Smuzhiyun * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
1064*4882a593Smuzhiyun * by the digital demod via calc_regs.
1065*4882a593Smuzhiyun */
1066*4882a593Smuzhiyun if (i2c_adap != NULL) {
1067*4882a593Smuzhiyun u8 b[1];
1068*4882a593Smuzhiyun struct i2c_msg msg = {
1069*4882a593Smuzhiyun .addr = i2c_addr, .flags = I2C_M_RD,
1070*4882a593Smuzhiyun .buf = b, .len = 1,
1071*4882a593Smuzhiyun };
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl)
1074*4882a593Smuzhiyun fe->ops.i2c_gate_ctrl(fe, 1);
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun if (1 != i2c_transfer(i2c_adap, &msg, 1))
1077*4882a593Smuzhiyun printk(KERN_WARNING "tuner-simple %d-%04x: unable to probe %s, proceeding anyway.",
1078*4882a593Smuzhiyun i2c_adapter_id(i2c_adap), i2c_addr,
1079*4882a593Smuzhiyun tuners[type].name);
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl)
1082*4882a593Smuzhiyun fe->ops.i2c_gate_ctrl(fe, 0);
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun mutex_lock(&tuner_simple_list_mutex);
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
1088*4882a593Smuzhiyun hybrid_tuner_instance_list,
1089*4882a593Smuzhiyun i2c_adap, i2c_addr,
1090*4882a593Smuzhiyun "tuner-simple");
1091*4882a593Smuzhiyun switch (instance) {
1092*4882a593Smuzhiyun case 0:
1093*4882a593Smuzhiyun mutex_unlock(&tuner_simple_list_mutex);
1094*4882a593Smuzhiyun return NULL;
1095*4882a593Smuzhiyun case 1:
1096*4882a593Smuzhiyun fe->tuner_priv = priv;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun priv->type = type;
1099*4882a593Smuzhiyun priv->tun = &tuners[type];
1100*4882a593Smuzhiyun priv->nr = simple_devcount++;
1101*4882a593Smuzhiyun break;
1102*4882a593Smuzhiyun default:
1103*4882a593Smuzhiyun fe->tuner_priv = priv;
1104*4882a593Smuzhiyun break;
1105*4882a593Smuzhiyun }
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun mutex_unlock(&tuner_simple_list_mutex);
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
1110*4882a593Smuzhiyun sizeof(struct dvb_tuner_ops));
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun if (type != priv->type)
1113*4882a593Smuzhiyun tuner_warn("couldn't set type to %d. Using %d (%s) instead\n",
1114*4882a593Smuzhiyun type, priv->type, priv->tun->name);
1115*4882a593Smuzhiyun else
1116*4882a593Smuzhiyun tuner_info("type set to %d (%s)\n",
1117*4882a593Smuzhiyun priv->type, priv->tun->name);
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun if ((debug) || ((atv_input[priv->nr] > 0) ||
1120*4882a593Smuzhiyun (dtv_input[priv->nr] > 0))) {
1121*4882a593Smuzhiyun if (0 == atv_input[priv->nr])
1122*4882a593Smuzhiyun tuner_info("tuner %d atv rf input will be autoselected\n",
1123*4882a593Smuzhiyun priv->nr);
1124*4882a593Smuzhiyun else
1125*4882a593Smuzhiyun tuner_info("tuner %d atv rf input will be set to input %d (insmod option)\n",
1126*4882a593Smuzhiyun priv->nr, atv_input[priv->nr]);
1127*4882a593Smuzhiyun if (0 == dtv_input[priv->nr])
1128*4882a593Smuzhiyun tuner_info("tuner %d dtv rf input will be autoselected\n",
1129*4882a593Smuzhiyun priv->nr);
1130*4882a593Smuzhiyun else
1131*4882a593Smuzhiyun tuner_info("tuner %d dtv rf input will be set to input %d (insmod option)\n",
1132*4882a593Smuzhiyun priv->nr, dtv_input[priv->nr]);
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun strscpy(fe->ops.tuner_ops.info.name, priv->tun->name,
1136*4882a593Smuzhiyun sizeof(fe->ops.tuner_ops.info.name));
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun return fe;
1139*4882a593Smuzhiyun }
1140*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(simple_tuner_attach);
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
1143*4882a593Smuzhiyun MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
1144*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1145