Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * i2c tv tuner chip device driver |
3 | * controls all those simple 4-control-bytes style tuners. | |
4adad287 MK |
4 | * |
5 | * This "tuner-simple" module was split apart from the original "tuner" module. | |
1da177e4 LT |
6 | */ |
7 | #include <linux/delay.h> | |
8 | #include <linux/i2c.h> | |
9 | #include <linux/videodev.h> | |
10 | #include <media/tuner.h> | |
ba8fc399 | 11 | #include <media/v4l2-common.h> |
8218b0b2 | 12 | #include <media/tuner-types.h> |
4adad287 MK |
13 | #include "tuner-i2c.h" |
14 | #include "tuner-simple.h" | |
15 | ||
9ba0a3c0 | 16 | static int debug; |
4adad287 MK |
17 | module_param(debug, int, 0644); |
18 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | |
19 | ||
9ba0a3c0 | 20 | static int offset; |
4d98816b | 21 | module_param(offset, int, 0664); |
9ba0a3c0 | 22 | MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); |
5c07db0c | 23 | |
1da177e4 LT |
24 | /* ---------------------------------------------------------------------- */ |
25 | ||
26 | /* tv standard selection for Temic 4046 FM5 | |
27 | this value takes the low bits of control byte 2 | |
28 | from datasheet Rev.01, Feb.00 | |
29 | standard BG I L L2 D | |
30 | picture IF 38.9 38.9 38.9 33.95 38.9 | |
31 | sound 1 33.4 32.9 32.4 40.45 32.4 | |
32 | sound 2 33.16 | |
33 | NICAM 33.05 32.348 33.05 33.05 | |
34 | */ | |
35 | #define TEMIC_SET_PAL_I 0x05 | |
36 | #define TEMIC_SET_PAL_DK 0x09 | |
9ba0a3c0 MK |
37 | #define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ |
38 | #define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ | |
1da177e4 LT |
39 | #define TEMIC_SET_PAL_BG 0x0c |
40 | ||
41 | /* tv tuner system standard selection for Philips FQ1216ME | |
42 | this value takes the low bits of control byte 2 | |
43 | from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") | |
44 | standard BG DK I L L` | |
45 | picture carrier 38.90 38.90 38.90 38.90 33.95 | |
46 | colour 34.47 34.47 34.47 34.47 38.38 | |
47 | sound 1 33.40 32.40 32.90 32.40 40.45 | |
48 | sound 2 33.16 - - - - | |
49 | NICAM 33.05 33.05 32.35 33.05 39.80 | |
50 | */ | |
51 | #define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ | |
52 | #define PHILIPS_SET_PAL_BGDK 0x09 | |
53 | #define PHILIPS_SET_PAL_L2 0x0a | |
54 | #define PHILIPS_SET_PAL_L 0x0b | |
55 | ||
56 | /* system switching for Philips FI1216MF MK2 | |
57 | from datasheet "1996 Jul 09", | |
58 | standard BG L L' | |
59 | picture carrier 38.90 38.90 33.95 | |
60 | colour 34.47 34.37 38.38 | |
61 | sound 1 33.40 32.40 40.45 | |
62 | sound 2 33.16 - - | |
63 | NICAM 33.05 33.05 39.80 | |
64 | */ | |
c57032de MCC |
65 | #define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ |
66 | #define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ | |
67 | #define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ | |
1da177e4 | 68 | |
f7ce3cc6 MCC |
69 | /* Control byte */ |
70 | ||
71 | #define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ | |
72 | #define TUNER_RATIO_SELECT_50 0x00 | |
73 | #define TUNER_RATIO_SELECT_32 0x02 | |
74 | #define TUNER_RATIO_SELECT_166 0x04 | |
75 | #define TUNER_RATIO_SELECT_62 0x06 | |
76 | ||
77 | #define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ | |
78 | ||
79 | /* Status byte */ | |
80 | ||
81 | #define TUNER_POR 0x80 | |
82 | #define TUNER_FL 0x40 | |
83 | #define TUNER_MODE 0x38 | |
84 | #define TUNER_AFC 0x07 | |
85 | #define TUNER_SIGNAL 0x07 | |
86 | #define TUNER_STEREO 0x10 | |
87 | ||
88 | #define TUNER_PLL_LOCKED 0x40 | |
89 | #define TUNER_STEREO_MK3 0x04 | |
1da177e4 | 90 | |
62325497 MK |
91 | static DEFINE_MUTEX(tuner_simple_list_mutex); |
92 | static LIST_HEAD(hybrid_tuner_instance_list); | |
93 | ||
6b1dde90 MK |
94 | struct tuner_simple_priv { |
95 | u16 last_div; | |
62325497 | 96 | |
db8a6956 | 97 | struct tuner_i2c_props i2c_props; |
62325497 | 98 | struct list_head hybrid_tuner_instance_list; |
4adad287 MK |
99 | |
100 | unsigned int type; | |
101 | struct tunertype *tun; | |
102 | ||
103 | u32 frequency; | |
62325497 | 104 | u32 bandwidth; |
6b1dde90 MK |
105 | }; |
106 | ||
1da177e4 LT |
107 | /* ---------------------------------------------------------------------- */ |
108 | ||
735f0b9a | 109 | static int tuner_read_status(struct dvb_frontend *fe) |
1da177e4 | 110 | { |
4adad287 | 111 | struct tuner_simple_priv *priv = fe->tuner_priv; |
1da177e4 LT |
112 | unsigned char byte; |
113 | ||
9ba0a3c0 | 114 | if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) |
1da177e4 | 115 | return 0; |
56fc08ca | 116 | |
1da177e4 LT |
117 | return byte; |
118 | } | |
119 | ||
735f0b9a | 120 | static inline int tuner_signal(const int status) |
1da177e4 | 121 | { |
735f0b9a | 122 | return (status & TUNER_SIGNAL) << 13; |
1da177e4 LT |
123 | } |
124 | ||
735f0b9a | 125 | static inline int tuner_stereo(const int type, const int status) |
1da177e4 | 126 | { |
735f0b9a | 127 | switch (type) { |
9ba0a3c0 MK |
128 | case TUNER_PHILIPS_FM1216ME_MK3: |
129 | case TUNER_PHILIPS_FM1236_MK3: | |
130 | case TUNER_PHILIPS_FM1256_IH3: | |
131 | case TUNER_LG_NTSC_TAPE: | |
132 | return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); | |
133 | default: | |
134 | return status & TUNER_STEREO; | |
56fc08ca | 135 | } |
735f0b9a | 136 | } |
56fc08ca | 137 | |
735f0b9a MK |
138 | static inline int tuner_islocked(const int status) |
139 | { | |
140 | return (status & TUNER_FL); | |
141 | } | |
142 | ||
143 | static inline int tuner_afcstatus(const int status) | |
144 | { | |
145 | return (status & TUNER_AFC) - 2; | |
1da177e4 LT |
146 | } |
147 | ||
1da177e4 | 148 | |
4adad287 MK |
149 | static int simple_get_status(struct dvb_frontend *fe, u32 *status) |
150 | { | |
151 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
a81df363 MK |
152 | int tuner_status; |
153 | ||
154 | if (priv->i2c_props.adap == NULL) | |
155 | return -EINVAL; | |
156 | ||
157 | tuner_status = tuner_read_status(fe); | |
4adad287 MK |
158 | |
159 | *status = 0; | |
160 | ||
735f0b9a | 161 | if (tuner_islocked(tuner_status)) |
4adad287 | 162 | *status = TUNER_STATUS_LOCKED; |
735f0b9a | 163 | if (tuner_stereo(priv->type, tuner_status)) |
4adad287 MK |
164 | *status |= TUNER_STATUS_STEREO; |
165 | ||
735f0b9a MK |
166 | tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
171 | static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | |
172 | { | |
173 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
a81df363 MK |
174 | int signal; |
175 | ||
176 | if (priv->i2c_props.adap == NULL) | |
177 | return -EINVAL; | |
178 | ||
179 | signal = tuner_signal(tuner_read_status(fe)); | |
735f0b9a MK |
180 | |
181 | *strength = signal; | |
182 | ||
183 | tuner_dbg("Signal strength: %d\n", signal); | |
4adad287 MK |
184 | |
185 | return 0; | |
186 | } | |
187 | ||
1da177e4 LT |
188 | /* ---------------------------------------------------------------------- */ |
189 | ||
be71f7dc MK |
190 | static inline char *tuner_param_name(enum param_type type) |
191 | { | |
192 | char *name; | |
193 | ||
194 | switch (type) { | |
195 | case TUNER_PARAM_TYPE_RADIO: | |
196 | name = "radio"; | |
197 | break; | |
198 | case TUNER_PARAM_TYPE_PAL: | |
199 | name = "pal"; | |
200 | break; | |
201 | case TUNER_PARAM_TYPE_SECAM: | |
202 | name = "secam"; | |
203 | break; | |
204 | case TUNER_PARAM_TYPE_NTSC: | |
205 | name = "ntsc"; | |
206 | break; | |
62325497 MK |
207 | case TUNER_PARAM_TYPE_DIGITAL: |
208 | name = "digital"; | |
209 | break; | |
be71f7dc MK |
210 | default: |
211 | name = "unknown"; | |
212 | break; | |
213 | } | |
214 | return name; | |
215 | } | |
216 | ||
217 | static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, | |
218 | enum param_type desired_type) | |
219 | { | |
220 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
221 | struct tunertype *tun = priv->tun; | |
222 | int i; | |
223 | ||
224 | for (i = 0; i < tun->count; i++) | |
225 | if (desired_type == tun->params[i].type) | |
226 | break; | |
227 | ||
228 | /* use default tuner params if desired_type not available */ | |
229 | if (i == tun->count) { | |
230 | tuner_dbg("desired params (%s) undefined for tuner %d\n", | |
231 | tuner_param_name(desired_type), priv->type); | |
232 | i = 0; | |
233 | } | |
234 | ||
235 | tuner_dbg("using tuner params #%d (%s)\n", i, | |
236 | tuner_param_name(tun->params[i].type)); | |
237 | ||
238 | return &tun->params[i]; | |
239 | } | |
240 | ||
241 | static int simple_config_lookup(struct dvb_frontend *fe, | |
242 | struct tuner_params *t_params, | |
243 | int *frequency, u8 *config, u8 *cb) | |
244 | { | |
245 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
246 | int i; | |
247 | ||
248 | for (i = 0; i < t_params->count; i++) { | |
249 | if (*frequency > t_params->ranges[i].limit) | |
250 | continue; | |
251 | break; | |
252 | } | |
253 | if (i == t_params->count) { | |
254 | tuner_dbg("frequency out of range (%d > %d)\n", | |
255 | *frequency, t_params->ranges[i - 1].limit); | |
256 | *frequency = t_params->ranges[--i].limit; | |
257 | } | |
258 | *config = t_params->ranges[i].config; | |
259 | *cb = t_params->ranges[i].cb; | |
260 | ||
7f8447d1 MK |
261 | tuner_dbg("freq = %d.%02d (%d), range = %d, " |
262 | "config = 0x%02x, cb = 0x%02x\n", | |
263 | *frequency / 16, *frequency % 16 * 100 / 16, *frequency, | |
264 | i, *config, *cb); | |
be71f7dc MK |
265 | |
266 | return i; | |
267 | } | |
268 | ||
269 | /* ---------------------------------------------------------------------- */ | |
270 | ||
c7a9f3aa MK |
271 | static int simple_std_setup(struct dvb_frontend *fe, |
272 | struct analog_parameters *params, | |
f13613ac | 273 | u8 *config, u8 *cb) |
1da177e4 | 274 | { |
4adad287 | 275 | struct tuner_simple_priv *priv = fe->tuner_priv; |
c7a9f3aa MK |
276 | u8 tuneraddr; |
277 | int rc; | |
5f594187 | 278 | |
1da177e4 | 279 | /* tv norm specific stuff for multi-norm tuners */ |
4adad287 | 280 | switch (priv->type) { |
9ba0a3c0 | 281 | case TUNER_PHILIPS_SECAM: /* FI1216MF */ |
1da177e4 LT |
282 | /* 0x01 -> ??? no change ??? */ |
283 | /* 0x02 -> PAL BDGHI / SECAM L */ | |
284 | /* 0x04 -> ??? PAL others / SECAM others ??? */ | |
c7a9f3aa | 285 | *cb &= ~0x03; |
9ba0a3c0 MK |
286 | if (params->std & V4L2_STD_SECAM_L) |
287 | /* also valid for V4L2_STD_SECAM */ | |
c7a9f3aa | 288 | *cb |= PHILIPS_MF_SET_STD_L; |
4adad287 | 289 | else if (params->std & V4L2_STD_SECAM_LC) |
c7a9f3aa | 290 | *cb |= PHILIPS_MF_SET_STD_LC; |
82c01d3d | 291 | else /* V4L2_STD_B|V4L2_STD_GH */ |
c7a9f3aa | 292 | *cb |= PHILIPS_MF_SET_STD_BG; |
1da177e4 LT |
293 | break; |
294 | ||
295 | case TUNER_TEMIC_4046FM5: | |
c7a9f3aa | 296 | *cb &= ~0x0f; |
1da177e4 | 297 | |
4adad287 | 298 | if (params->std & V4L2_STD_PAL_BG) { |
c7a9f3aa | 299 | *cb |= TEMIC_SET_PAL_BG; |
1da177e4 | 300 | |
4adad287 | 301 | } else if (params->std & V4L2_STD_PAL_I) { |
c7a9f3aa | 302 | *cb |= TEMIC_SET_PAL_I; |
1da177e4 | 303 | |
4adad287 | 304 | } else if (params->std & V4L2_STD_PAL_DK) { |
c7a9f3aa | 305 | *cb |= TEMIC_SET_PAL_DK; |
1da177e4 | 306 | |
4adad287 | 307 | } else if (params->std & V4L2_STD_SECAM_L) { |
c7a9f3aa | 308 | *cb |= TEMIC_SET_PAL_L; |
1da177e4 LT |
309 | |
310 | } | |
311 | break; | |
312 | ||
313 | case TUNER_PHILIPS_FQ1216ME: | |
c7a9f3aa | 314 | *cb &= ~0x0f; |
1da177e4 | 315 | |
4adad287 | 316 | if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { |
c7a9f3aa | 317 | *cb |= PHILIPS_SET_PAL_BGDK; |
1da177e4 | 318 | |
4adad287 | 319 | } else if (params->std & V4L2_STD_PAL_I) { |
c7a9f3aa | 320 | *cb |= PHILIPS_SET_PAL_I; |
1da177e4 | 321 | |
4adad287 | 322 | } else if (params->std & V4L2_STD_SECAM_L) { |
c7a9f3aa | 323 | *cb |= PHILIPS_SET_PAL_L; |
1da177e4 LT |
324 | |
325 | } | |
326 | break; | |
327 | ||
328 | case TUNER_PHILIPS_ATSC: | |
329 | /* 0x00 -> ATSC antenna input 1 */ | |
330 | /* 0x01 -> ATSC antenna input 2 */ | |
331 | /* 0x02 -> NTSC antenna input 1 */ | |
332 | /* 0x03 -> NTSC antenna input 2 */ | |
c7a9f3aa | 333 | *cb &= ~0x03; |
4adad287 | 334 | if (!(params->std & V4L2_STD_ATSC)) |
c7a9f3aa | 335 | *cb |= 2; |
1da177e4 LT |
336 | /* FIXME: input */ |
337 | break; | |
338 | ||
339 | case TUNER_MICROTUNE_4042FI5: | |
340 | /* Set the charge pump for fast tuning */ | |
c7a9f3aa | 341 | *config |= TUNER_CHARGE_PUMP; |
1da177e4 | 342 | break; |
e976f937 KL |
343 | |
344 | case TUNER_PHILIPS_TUV1236D: | |
f13613ac | 345 | { |
e976f937 KL |
346 | /* 0x40 -> ATSC antenna input 1 */ |
347 | /* 0x48 -> ATSC antenna input 2 */ | |
348 | /* 0x00 -> NTSC antenna input 1 */ | |
349 | /* 0x08 -> NTSC antenna input 2 */ | |
f13613ac | 350 | u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; |
c7a9f3aa | 351 | *cb &= ~0x40; |
4adad287 | 352 | if (params->std & V4L2_STD_ATSC) { |
c7a9f3aa | 353 | *cb |= 0x40; |
fde6d31e KL |
354 | buffer[1] = 0x04; |
355 | } | |
356 | /* set to the correct mode (analog or digital) */ | |
db8a6956 MK |
357 | tuneraddr = priv->i2c_props.addr; |
358 | priv->i2c_props.addr = 0x0a; | |
9ba0a3c0 MK |
359 | rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2); |
360 | if (2 != rc) | |
361 | tuner_warn("i2c i/o error: rc == %d " | |
362 | "(should be 2)\n", rc); | |
363 | rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2); | |
364 | if (2 != rc) | |
365 | tuner_warn("i2c i/o error: rc == %d " | |
366 | "(should be 2)\n", rc); | |
db8a6956 | 367 | priv->i2c_props.addr = tuneraddr; |
e976f937 KL |
368 | /* FIXME: input */ |
369 | break; | |
1da177e4 | 370 | } |
f13613ac | 371 | } |
1da177e4 | 372 | |
c7a9f3aa MK |
373 | return 0; |
374 | } | |
375 | ||
376 | static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, | |
377 | u16 div, u8 config, u8 cb) | |
378 | { | |
379 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
380 | int rc; | |
381 | ||
382 | switch (priv->type) { | |
383 | case TUNER_LG_TDVS_H06XF: | |
384 | /* Set the Auxiliary Byte. */ | |
385 | buffer[0] = buffer[2]; | |
386 | buffer[0] &= ~0x20; | |
387 | buffer[0] |= 0x18; | |
388 | buffer[1] = 0x20; | |
389 | tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]); | |
390 | ||
391 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); | |
392 | if (2 != rc) | |
393 | tuner_warn("i2c i/o error: rc == %d " | |
394 | "(should be 2)\n", rc); | |
395 | break; | |
396 | case TUNER_MICROTUNE_4042FI5: | |
397 | { | |
398 | /* FIXME - this may also work for other tuners */ | |
399 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | |
400 | u8 status_byte = 0; | |
401 | ||
402 | /* Wait until the PLL locks */ | |
403 | for (;;) { | |
404 | if (time_after(jiffies, timeout)) | |
405 | return 0; | |
406 | rc = tuner_i2c_xfer_recv(&priv->i2c_props, | |
407 | &status_byte, 1); | |
408 | if (1 != rc) { | |
409 | tuner_warn("i2c i/o read error: rc == %d " | |
410 | "(should be 1)\n", rc); | |
411 | break; | |
412 | } | |
413 | if (status_byte & TUNER_PLL_LOCKED) | |
414 | break; | |
415 | udelay(10); | |
416 | } | |
417 | ||
418 | /* Set the charge pump for optimized phase noise figure */ | |
419 | config &= ~TUNER_CHARGE_PUMP; | |
420 | buffer[0] = (div>>8) & 0x7f; | |
421 | buffer[1] = div & 0xff; | |
422 | buffer[2] = config; | |
423 | buffer[3] = cb; | |
424 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", | |
425 | buffer[0], buffer[1], buffer[2], buffer[3]); | |
426 | ||
427 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | |
428 | if (4 != rc) | |
429 | tuner_warn("i2c i/o error: rc == %d " | |
430 | "(should be 4)\n", rc); | |
431 | break; | |
432 | } | |
433 | } | |
434 | ||
435 | return 0; | |
436 | } | |
437 | ||
438 | static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) | |
439 | { | |
440 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
441 | ||
442 | switch (priv->type) { | |
443 | case TUNER_TENA_9533_DI: | |
444 | case TUNER_YMEC_TVF_5533MF: | |
445 | tuner_dbg("This tuner doesn't have FM. " | |
446 | "Most cards have a TEA5767 for FM\n"); | |
447 | return 0; | |
448 | case TUNER_PHILIPS_FM1216ME_MK3: | |
449 | case TUNER_PHILIPS_FM1236_MK3: | |
450 | case TUNER_PHILIPS_FMD1216ME_MK3: | |
451 | case TUNER_LG_NTSC_TAPE: | |
452 | case TUNER_PHILIPS_FM1256_IH3: | |
453 | buffer[3] = 0x19; | |
454 | break; | |
455 | case TUNER_TNF_5335MF: | |
456 | buffer[3] = 0x11; | |
457 | break; | |
458 | case TUNER_LG_PAL_FM: | |
459 | buffer[3] = 0xa5; | |
460 | break; | |
461 | case TUNER_THOMSON_DTT761X: | |
462 | buffer[3] = 0x39; | |
463 | break; | |
464 | case TUNER_MICROTUNE_4049FM5: | |
465 | default: | |
466 | buffer[3] = 0xa4; | |
467 | break; | |
468 | } | |
469 | ||
470 | return 0; | |
471 | } | |
472 | ||
473 | /* ---------------------------------------------------------------------- */ | |
474 | ||
475 | static int simple_set_tv_freq(struct dvb_frontend *fe, | |
476 | struct analog_parameters *params) | |
477 | { | |
478 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
479 | u8 config, cb; | |
480 | u16 div; | |
481 | struct tunertype *tun; | |
482 | u8 buffer[4]; | |
483 | int rc, IFPCoff, i; | |
484 | enum param_type desired_type; | |
485 | struct tuner_params *t_params; | |
486 | ||
487 | tun = priv->tun; | |
488 | ||
489 | /* IFPCoff = Video Intermediate Frequency - Vif: | |
490 | 940 =16*58.75 NTSC/J (Japan) | |
491 | 732 =16*45.75 M/N STD | |
492 | 704 =16*44 ATSC (at DVB code) | |
493 | 632 =16*39.50 I U.K. | |
494 | 622.4=16*38.90 B/G D/K I, L STD | |
495 | 592 =16*37.00 D China | |
496 | 590 =16.36.875 B Australia | |
497 | 543.2=16*33.95 L' STD | |
498 | 171.2=16*10.70 FM Radio (at set_radio_freq) | |
499 | */ | |
500 | ||
501 | if (params->std == V4L2_STD_NTSC_M_JP) { | |
502 | IFPCoff = 940; | |
503 | desired_type = TUNER_PARAM_TYPE_NTSC; | |
504 | } else if ((params->std & V4L2_STD_MN) && | |
505 | !(params->std & ~V4L2_STD_MN)) { | |
506 | IFPCoff = 732; | |
507 | desired_type = TUNER_PARAM_TYPE_NTSC; | |
508 | } else if (params->std == V4L2_STD_SECAM_LC) { | |
509 | IFPCoff = 543; | |
510 | desired_type = TUNER_PARAM_TYPE_SECAM; | |
511 | } else { | |
512 | IFPCoff = 623; | |
513 | desired_type = TUNER_PARAM_TYPE_PAL; | |
514 | } | |
515 | ||
516 | t_params = simple_tuner_params(fe, desired_type); | |
517 | ||
518 | i = simple_config_lookup(fe, t_params, ¶ms->frequency, | |
519 | &config, &cb); | |
520 | ||
521 | div = params->frequency + IFPCoff + offset; | |
522 | ||
523 | tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " | |
524 | "Offset=%d.%02d MHz, div=%0d\n", | |
525 | params->frequency / 16, params->frequency % 16 * 100 / 16, | |
526 | IFPCoff / 16, IFPCoff % 16 * 100 / 16, | |
527 | offset / 16, offset % 16 * 100 / 16, div); | |
528 | ||
529 | /* tv norm specific stuff for multi-norm tuners */ | |
f13613ac | 530 | simple_std_setup(fe, params, &config, &cb); |
c7a9f3aa | 531 | |
4adad287 | 532 | if (t_params->cb_first_if_lower_freq && div < priv->last_div) { |
3fc46d35 | 533 | buffer[0] = config; |
ab66b22f | 534 | buffer[1] = cb; |
1da177e4 LT |
535 | buffer[2] = (div>>8) & 0x7f; |
536 | buffer[3] = div & 0xff; | |
537 | } else { | |
538 | buffer[0] = (div>>8) & 0x7f; | |
539 | buffer[1] = div & 0xff; | |
3fc46d35 | 540 | buffer[2] = config; |
ab66b22f | 541 | buffer[3] = cb; |
1da177e4 | 542 | } |
6b1dde90 | 543 | priv->last_div = div; |
4adad287 | 544 | if (t_params->has_tda9887) { |
7f171123 | 545 | struct v4l2_priv_tun_config tda9887_cfg; |
ba8fc399 | 546 | int config = 0; |
9ba0a3c0 MK |
547 | int is_secam_l = (params->std & (V4L2_STD_SECAM_L | |
548 | V4L2_STD_SECAM_LC)) && | |
549 | !(params->std & ~(V4L2_STD_SECAM_L | | |
550 | V4L2_STD_SECAM_LC)); | |
ba8fc399 | 551 | |
7f171123 MCC |
552 | tda9887_cfg.tuner = TUNER_TDA9887; |
553 | tda9887_cfg.priv = &config; | |
554 | ||
4adad287 MK |
555 | if (params->std == V4L2_STD_SECAM_LC) { |
556 | if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) | |
ba8fc399 | 557 | config |= TDA9887_PORT1_ACTIVE; |
4adad287 | 558 | if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) |
ba8fc399 | 559 | config |= TDA9887_PORT2_ACTIVE; |
9ba0a3c0 | 560 | } else { |
4adad287 | 561 | if (t_params->port1_active) |
ba8fc399 | 562 | config |= TDA9887_PORT1_ACTIVE; |
4adad287 | 563 | if (t_params->port2_active) |
ba8fc399 HV |
564 | config |= TDA9887_PORT2_ACTIVE; |
565 | } | |
4adad287 | 566 | if (t_params->intercarrier_mode) |
ba8fc399 HV |
567 | config |= TDA9887_INTERCARRIER; |
568 | if (is_secam_l) { | |
4adad287 MK |
569 | if (i == 0 && t_params->default_top_secam_low) |
570 | config |= TDA9887_TOP(t_params->default_top_secam_low); | |
571 | else if (i == 1 && t_params->default_top_secam_mid) | |
572 | config |= TDA9887_TOP(t_params->default_top_secam_mid); | |
573 | else if (t_params->default_top_secam_high) | |
574 | config |= TDA9887_TOP(t_params->default_top_secam_high); | |
9ba0a3c0 | 575 | } else { |
4adad287 MK |
576 | if (i == 0 && t_params->default_top_low) |
577 | config |= TDA9887_TOP(t_params->default_top_low); | |
578 | else if (i == 1 && t_params->default_top_mid) | |
579 | config |= TDA9887_TOP(t_params->default_top_mid); | |
580 | else if (t_params->default_top_high) | |
581 | config |= TDA9887_TOP(t_params->default_top_high); | |
ba8fc399 | 582 | } |
4adad287 | 583 | if (t_params->default_pll_gating_18) |
d7304dee | 584 | config |= TDA9887_GATING_18; |
7f171123 MCC |
585 | i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, |
586 | &tda9887_cfg); | |
ba8fc399 | 587 | } |
1da177e4 | 588 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", |
9ba0a3c0 | 589 | buffer[0], buffer[1], buffer[2], buffer[3]); |
1da177e4 | 590 | |
9ba0a3c0 MK |
591 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); |
592 | if (4 != rc) | |
593 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | |
1da177e4 | 594 | |
c7a9f3aa | 595 | simple_post_tune(fe, &buffer[0], div, config, cb); |
1da177e4 | 596 | |
4adad287 | 597 | return 0; |
1da177e4 LT |
598 | } |
599 | ||
4adad287 MK |
600 | static int simple_set_radio_freq(struct dvb_frontend *fe, |
601 | struct analog_parameters *params) | |
1da177e4 LT |
602 | { |
603 | struct tunertype *tun; | |
4adad287 | 604 | struct tuner_simple_priv *priv = fe->tuner_priv; |
27487d44 HV |
605 | u8 buffer[4]; |
606 | u16 div; | |
7b0ac9cd | 607 | int rc, j; |
4adad287 MK |
608 | struct tuner_params *t_params; |
609 | unsigned int freq = params->frequency; | |
1da177e4 | 610 | |
4adad287 | 611 | tun = priv->tun; |
476d63d0 | 612 | |
5e082f15 TP |
613 | for (j = tun->count-1; j > 0; j--) |
614 | if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) | |
615 | break; | |
4adad287 MK |
616 | /* default t_params (j=0) will be used if desired type wasn't found */ |
617 | t_params = &tun->params[j]; | |
5e082f15 TP |
618 | |
619 | /* Select Radio 1st IF used */ | |
4adad287 | 620 | switch (t_params->radio_if) { |
5e082f15 TP |
621 | case 0: /* 10.7 MHz */ |
622 | freq += (unsigned int)(10.7*16000); | |
476d63d0 | 623 | break; |
5e082f15 TP |
624 | case 1: /* 33.3 MHz */ |
625 | freq += (unsigned int)(33.3*16000); | |
626 | break; | |
627 | case 2: /* 41.3 MHz */ | |
628 | freq += (unsigned int)(41.3*16000); | |
629 | break; | |
630 | default: | |
9ba0a3c0 MK |
631 | tuner_warn("Unsupported radio_if value %d\n", |
632 | t_params->radio_if); | |
4adad287 | 633 | return 0; |
476d63d0 | 634 | } |
1da177e4 | 635 | |
5e082f15 | 636 | /* Bandswitch byte */ |
c7a9f3aa | 637 | simple_radio_bandswitch(fe, &buffer[0]); |
5e082f15 | 638 | |
4adad287 | 639 | buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | |
5e082f15 TP |
640 | TUNER_RATIO_SELECT_50; /* 50 kHz step */ |
641 | ||
642 | /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps | |
643 | freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = | |
644 | freq * (1/800) */ | |
645 | div = (freq + 400) / 800; | |
646 | ||
4adad287 | 647 | if (t_params->cb_first_if_lower_freq && div < priv->last_div) { |
27487d44 HV |
648 | buffer[0] = buffer[2]; |
649 | buffer[1] = buffer[3]; | |
650 | buffer[2] = (div>>8) & 0x7f; | |
651 | buffer[3] = div & 0xff; | |
652 | } else { | |
653 | buffer[0] = (div>>8) & 0x7f; | |
654 | buffer[1] = div & 0xff; | |
655 | } | |
1da177e4 LT |
656 | |
657 | tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", | |
9ba0a3c0 | 658 | buffer[0], buffer[1], buffer[2], buffer[3]); |
6b1dde90 | 659 | priv->last_div = div; |
1da177e4 | 660 | |
4adad287 | 661 | if (t_params->has_tda9887) { |
ba8fc399 | 662 | int config = 0; |
7f171123 MCC |
663 | struct v4l2_priv_tun_config tda9887_cfg; |
664 | ||
665 | tda9887_cfg.tuner = TUNER_TDA9887; | |
666 | tda9887_cfg.priv = &config; | |
667 | ||
9ba0a3c0 MK |
668 | if (t_params->port1_active && |
669 | !t_params->port1_fm_high_sensitivity) | |
ba8fc399 | 670 | config |= TDA9887_PORT1_ACTIVE; |
9ba0a3c0 MK |
671 | if (t_params->port2_active && |
672 | !t_params->port2_fm_high_sensitivity) | |
ba8fc399 | 673 | config |= TDA9887_PORT2_ACTIVE; |
4adad287 | 674 | if (t_params->intercarrier_mode) |
ba8fc399 | 675 | config |= TDA9887_INTERCARRIER; |
4adad287 | 676 | /* if (t_params->port1_set_for_fm_mono) |
ba8fc399 | 677 | config &= ~TDA9887_PORT1_ACTIVE;*/ |
4adad287 | 678 | if (t_params->fm_gain_normal) |
483deb0f | 679 | config |= TDA9887_GAIN_NORMAL; |
4adad287 | 680 | if (t_params->radio_if == 2) |
5e082f15 | 681 | config |= TDA9887_RIF_41_3; |
7f171123 | 682 | i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, |
9ba0a3c0 | 683 | &tda9887_cfg); |
ba8fc399 | 684 | } |
9ba0a3c0 MK |
685 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); |
686 | if (4 != rc) | |
687 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | |
4adad287 MK |
688 | |
689 | return 0; | |
1da177e4 LT |
690 | } |
691 | ||
4adad287 MK |
692 | static int simple_set_params(struct dvb_frontend *fe, |
693 | struct analog_parameters *params) | |
6b1dde90 | 694 | { |
4adad287 MK |
695 | struct tuner_simple_priv *priv = fe->tuner_priv; |
696 | int ret = -EINVAL; | |
697 | ||
a81df363 MK |
698 | if (priv->i2c_props.adap == NULL) |
699 | return -EINVAL; | |
700 | ||
4adad287 MK |
701 | switch (params->mode) { |
702 | case V4L2_TUNER_RADIO: | |
703 | ret = simple_set_radio_freq(fe, params); | |
704 | priv->frequency = params->frequency * 125 / 2; | |
705 | break; | |
706 | case V4L2_TUNER_ANALOG_TV: | |
707 | case V4L2_TUNER_DIGITAL_TV: | |
708 | ret = simple_set_tv_freq(fe, params); | |
709 | priv->frequency = params->frequency * 62500; | |
710 | break; | |
711 | } | |
62325497 | 712 | priv->bandwidth = 0; |
4adad287 MK |
713 | |
714 | return ret; | |
715 | } | |
716 | ||
62325497 MK |
717 | static int simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, |
718 | const struct dvb_frontend_parameters *params) | |
719 | { | |
720 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
721 | struct tunertype *tun = priv->tun; | |
722 | static struct tuner_params *t_params; | |
723 | u8 config, cb; | |
724 | u32 div; | |
725 | int ret, frequency = params->frequency / 62500; | |
726 | ||
727 | t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); | |
728 | ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); | |
729 | if (ret < 0) | |
730 | return ret; | |
731 | ||
732 | div = ((frequency + t_params->iffreq) * 62500 + offset + | |
733 | tun->stepsize/2) / tun->stepsize; | |
734 | ||
735 | buf[0] = div >> 8; | |
736 | buf[1] = div & 0xff; | |
737 | buf[2] = config; | |
738 | buf[3] = cb; | |
739 | ||
740 | tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", | |
741 | tun->name, div, buf[0], buf[1], buf[2], buf[3]); | |
742 | ||
743 | /* calculate the frequency we set it to */ | |
744 | return (div * tun->stepsize) - t_params->iffreq; | |
745 | } | |
746 | ||
747 | static int simple_dvb_calc_regs(struct dvb_frontend *fe, | |
748 | struct dvb_frontend_parameters *params, | |
749 | u8 *buf, int buf_len) | |
750 | { | |
751 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
752 | int ret; | |
753 | u32 frequency; | |
754 | ||
755 | if (buf_len < 5) | |
756 | return -EINVAL; | |
757 | ||
758 | ret = simple_dvb_configure(fe, buf+1, params); | |
759 | if (ret < 0) | |
760 | return ret; | |
761 | else | |
762 | frequency = ret; | |
763 | ||
764 | buf[0] = priv->i2c_props.addr; | |
765 | ||
766 | priv->frequency = frequency; | |
767 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? | |
768 | params->u.ofdm.bandwidth : 0; | |
769 | ||
770 | return 5; | |
771 | } | |
772 | ||
773 | static int simple_dvb_set_params(struct dvb_frontend *fe, | |
774 | struct dvb_frontend_parameters *params) | |
775 | { | |
776 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
777 | u32 prev_freq, prev_bw; | |
778 | int ret; | |
779 | u8 buf[5]; | |
780 | ||
781 | if (priv->i2c_props.adap == NULL) | |
782 | return -EINVAL; | |
783 | ||
784 | prev_freq = priv->frequency; | |
785 | prev_bw = priv->bandwidth; | |
786 | ||
787 | ret = simple_dvb_calc_regs(fe, params, buf, 5); | |
788 | if (ret != 5) | |
789 | goto fail; | |
790 | ||
791 | /* put analog demod in standby when tuning digital */ | |
792 | if (fe->ops.analog_ops.standby) | |
793 | fe->ops.analog_ops.standby(fe); | |
794 | ||
795 | if (fe->ops.i2c_gate_ctrl) | |
796 | fe->ops.i2c_gate_ctrl(fe, 1); | |
797 | ||
798 | /* buf[0] contains the i2c address, but * | |
799 | * we already have it in i2c_props.addr */ | |
800 | ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); | |
801 | if (ret != 4) | |
802 | goto fail; | |
803 | ||
804 | return 0; | |
805 | fail: | |
806 | /* calc_regs sets frequency and bandwidth. if we failed, unset them */ | |
807 | priv->frequency = prev_freq; | |
808 | priv->bandwidth = prev_bw; | |
809 | ||
810 | return ret; | |
811 | } | |
4adad287 MK |
812 | |
813 | static int simple_release(struct dvb_frontend *fe) | |
814 | { | |
62325497 MK |
815 | struct tuner_simple_priv *priv = fe->tuner_priv; |
816 | ||
817 | mutex_lock(&tuner_simple_list_mutex); | |
818 | ||
819 | if (priv) | |
820 | hybrid_tuner_release_state(priv); | |
821 | ||
822 | mutex_unlock(&tuner_simple_list_mutex); | |
823 | ||
4adad287 MK |
824 | fe->tuner_priv = NULL; |
825 | ||
826 | return 0; | |
827 | } | |
828 | ||
829 | static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |
830 | { | |
831 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
832 | *frequency = priv->frequency; | |
833 | return 0; | |
6b1dde90 MK |
834 | } |
835 | ||
62325497 MK |
836 | static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) |
837 | { | |
838 | struct tuner_simple_priv *priv = fe->tuner_priv; | |
839 | *bandwidth = priv->bandwidth; | |
840 | return 0; | |
841 | } | |
842 | ||
4adad287 MK |
843 | static struct dvb_tuner_ops simple_tuner_ops = { |
844 | .set_analog_params = simple_set_params, | |
62325497 MK |
845 | .set_params = simple_dvb_set_params, |
846 | .calc_regs = simple_dvb_calc_regs, | |
735f0b9a MK |
847 | .release = simple_release, |
848 | .get_frequency = simple_get_frequency, | |
62325497 | 849 | .get_bandwidth = simple_get_bandwidth, |
735f0b9a MK |
850 | .get_status = simple_get_status, |
851 | .get_rf_strength = simple_get_rf_strength, | |
5d807c9f MK |
852 | }; |
853 | ||
4adad287 MK |
854 | struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, |
855 | struct i2c_adapter *i2c_adap, | |
856 | u8 i2c_addr, | |
060a5bd7 | 857 | unsigned int type) |
1da177e4 | 858 | { |
6b1dde90 | 859 | struct tuner_simple_priv *priv = NULL; |
62325497 | 860 | int instance; |
6b1dde90 | 861 | |
65e8d29f MK |
862 | if (type >= tuner_count) { |
863 | printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", | |
864 | __FUNCTION__, type, tuner_count-1); | |
865 | return NULL; | |
866 | } | |
867 | ||
62325497 MK |
868 | mutex_lock(&tuner_simple_list_mutex); |
869 | ||
870 | instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, | |
871 | hybrid_tuner_instance_list, | |
872 | i2c_adap, i2c_addr, | |
873 | "tuner-simple"); | |
874 | switch (instance) { | |
875 | case 0: | |
876 | mutex_unlock(&tuner_simple_list_mutex); | |
4adad287 | 877 | return NULL; |
62325497 MK |
878 | break; |
879 | case 1: | |
880 | fe->tuner_priv = priv; | |
1da177e4 | 881 | |
62325497 MK |
882 | priv->type = type; |
883 | priv->tun = &tuners[type]; | |
884 | break; | |
885 | default: | |
886 | fe->tuner_priv = priv; | |
887 | break; | |
888 | } | |
2756665c | 889 | |
62325497 | 890 | mutex_unlock(&tuner_simple_list_mutex); |
db8a6956 | 891 | |
9ba0a3c0 MK |
892 | memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, |
893 | sizeof(struct dvb_tuner_ops)); | |
1da177e4 | 894 | |
62325497 | 895 | tuner_info("type set to %d (%s)\n", type, priv->tun->name); |
586b0cab | 896 | |
060a5bd7 | 897 | strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, |
9ba0a3c0 | 898 | sizeof(fe->ops.tuner_ops.info.name)); |
4adad287 MK |
899 | |
900 | return fe; | |
1da177e4 | 901 | } |
4adad287 MK |
902 | EXPORT_SYMBOL_GPL(simple_tuner_attach); |
903 | ||
904 | MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); | |
905 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | |
906 | MODULE_LICENSE("GPL"); | |
907 | ||
1da177e4 LT |
908 | /* |
909 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
910 | * --------------------------------------------------------------------------- | |
911 | * Local variables: | |
912 | * c-basic-offset: 8 | |
913 | * End: | |
914 | */ |