2 * Copyright (c) 2003, 2004, 2005
3 * John Wehle <john@feith.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Wehle.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Tuner routines for the Conexant MPEG-2 Codec driver.
35 * Ideally these routines should be implemented as a separate
36 * driver which has a generic tuner interface so that it's
37 * not necessary for each multimedia driver to re-invent the
41 #include <sys/param.h>
42 #include <sys/systm.h>
45 #include <sys/kernel.h>
47 #include <sys/select.h>
48 #include <sys/resource.h>
52 #include <machine/clock.h>
54 #include <dev/video/meteor/ioctl_meteor.h>
55 #include <dev/video/bktr/ioctl_bt848.h>
57 #include <dev/video/cxm/cxm.h>
59 #include <bus/iicbus/iiconf.h>
60 #include <bus/iicbus/iicbus.h>
66 * Channel mappings derived from
67 * http://developer.apple.com/technotes/tn/tn1012.html
69 * B/G Cable mapping based the bktr Western European mapping
72 static const struct cxm_tuner_channels
76 CXM_TUNER_TV_SYSTEM_MN,
80 { { 14, 471250, 6000 },
86 static const struct cxm_tuner_channels
90 CXM_TUNER_TV_SYSTEM_MN,
94 { { 100, 649250, 6000 },
104 static const struct cxm_tuner_channels
108 CXM_TUNER_TV_SYSTEM_BG,
112 { { 82, 175250, 7000 },
114 { 79, 217250, 7000 },
115 { 77, 209250, 7000 },
116 { 76, 138250, 9000 },
117 { 75, 102250, 9000 },
121 { 21, 471250, 8000 },
122 { 20, 210250, 8500 },
123 { 18, 192750, 8500 },
124 { 16, 175250, 8000 },
131 static const struct cxm_tuner_channels
132 bg_cable_channels = {
135 CXM_TUNER_TV_SYSTEM_BG,
139 { { 100, 303250, 8000 },
140 { 90, 231250, 7000 },
141 { 80, 105250, 7000 },
148 { 21, 471250, 8000 },
149 { 20, 210250, 8500 },
150 { 18, 192750, 8500 },
151 { 16, 175250, 8000 },
158 static const struct cxm_tuner_channels
159 bg_australia_channels = {
162 CXM_TUNER_TV_SYSTEM_BG,
166 { { 28, 527250, 7000 },
167 { 10, 209250, 7000 },
174 static const struct cxm_tuner_channels
178 CXM_TUNER_TV_SYSTEM_I,
182 { { 75, 179750, 5000 },
185 { 21, 471250, 8000 },
193 { 13, 247250, 8000 },
199 static const struct cxm_tuner_channels
203 CXM_TUNER_TV_SYSTEM_L,
207 { { 21, 471250, 8000 },
223 static const struct cxm_tuner_channels
224 japan_air_channels = {
227 CXM_TUNER_TV_SYSTEM_MN,
231 { { 13, 471250, 6000 },
237 static const struct cxm_tuner_channels
238 japan_cable_channels = {
241 CXM_TUNER_TV_SYSTEM_MN,
245 { { 23, 223250, 6000 },
246 { 22, 165250, 6000 },
247 { 13, 109250, 6000 },
254 static const struct cxm_tuner_channels
260 &bg_australia_channels,
264 &japan_cable_channels
268 const struct cxm_tuner
269 cxm_tuners[CXM_TUNER_TYPES] = {
270 { "Philips FI1216 MK2",
271 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
273 { { 450000, { 0x8e, 0x30 } },
274 { 170000, { 0x8e, 0x90 } },
275 { 48250, { 0x8e, 0xa0 } } },
280 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
282 { { 450000, { 0xce, 0x30 } },
283 { 170000, { 0xce, 0x90 } },
284 { 48250, { 0xce, 0xa0 } } },
286 { 87500, { 0x88, 0xa5 } },
288 { "Philips FQ1216ME",
289 { CXM_TUNER_TV_SYSTEM_BG | CXM_TUNER_TV_SYSTEM_DK
290 | CXM_TUNER_TV_SYSTEM_I
291 | CXM_TUNER_TV_SYSTEM_L | CXM_TUNER_TV_SYSTEM_L_PRIME,
292 cxm_port_system_code_style,
293 { { CXM_TUNER_TV_SYSTEM_BG, { 0x09 } },
294 { CXM_TUNER_TV_SYSTEM_DK, { 0x09 } },
295 { CXM_TUNER_TV_SYSTEM_I, { 0x01 } },
296 { CXM_TUNER_TV_SYSTEM_L, { 0x0b } },
297 { CXM_TUNER_TV_SYSTEM_L_PRIME, { 0x0a } } } },
299 { { 450000, { 0x8e, 0x30 } },
300 { 170000, { 0x8e, 0x90 } },
301 { 48250, { 0x8e, 0xa0 } } },
305 { "Philips FQ1216ME MK3",
306 { CXM_TUNER_TV_SYSTEM_BG | CXM_TUNER_TV_SYSTEM_DK
307 | CXM_TUNER_TV_SYSTEM_I
308 | CXM_TUNER_TV_SYSTEM_L | CXM_TUNER_TV_SYSTEM_L_PRIME,
309 cxm_if_system_with_aux_code_style,
310 { { CXM_TUNER_TV_SYSTEM_BG, { 0x16, 0x70, 0x49, 0x40 }},
311 { CXM_TUNER_TV_SYSTEM_DK, { 0x16, 0x70, 0x4b, 0x40 }},
312 { CXM_TUNER_TV_SYSTEM_I, { 0x16, 0x70, 0x4a, 0x40 }},
313 { CXM_TUNER_TV_SYSTEM_L, { 0x06, 0x50, 0x4b, 0x50 }},
314 { CXM_TUNER_TV_SYSTEM_L_PRIME, { 0x86, 0x50, 0x53, 0x50 }}
317 { { 442000, { 0xce, 0x04 } },
318 { 160000, { 0xce, 0x02 } },
319 { 48250, { 0xce, 0x01 } } },
323 { "Philips FM1216ME MK3",
324 { CXM_TUNER_TV_SYSTEM_BG | CXM_TUNER_TV_SYSTEM_DK
325 | CXM_TUNER_TV_SYSTEM_I
326 | CXM_TUNER_TV_SYSTEM_L | CXM_TUNER_TV_SYSTEM_L_PRIME,
327 cxm_if_system_with_aux_code_style,
328 { { CXM_TUNER_TV_SYSTEM_BG, { 0x16, 0x70, 0x49, 0x40 }},
329 { CXM_TUNER_TV_SYSTEM_DK, { 0x16, 0x70, 0x4b, 0x40 }},
330 { CXM_TUNER_TV_SYSTEM_I, { 0x16, 0x70, 0x4a, 0x40 }},
331 { CXM_TUNER_TV_SYSTEM_L, { 0x06, 0x50, 0x4b, 0x50 }},
332 { CXM_TUNER_TV_SYSTEM_L_PRIME, { 0x86, 0x50, 0x53, 0x50 }},
333 { CXM_TUNER_FM_SYSTEM, { 0x0a, 0x90, 0x20, 0x40 }}
336 { { 442000, { 0xce, 0x04 } },
337 { 160000, { 0xce, 0x02 } },
338 { 48250, { 0xce, 0x01 } } },
340 { 87500, { 0x88, 0x19 } },
342 { "Philips FI1236 MK2",
343 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
345 { { 454000, { 0x8e, 0x30 } },
346 { 160000, { 0x8e, 0x90 } },
347 { 55250, { 0x8e, 0xa0 } } },
350 &us_cable_channels },
352 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
354 { { 454000, { 0xce, 0x30 } },
355 { 160000, { 0xce, 0x90 } },
356 { 55250, { 0xce, 0xa0 } } },
358 { 76000, { 0x88, 0xa5 } },
359 &us_cable_channels },
360 { "Philips FI1246 MK2",
361 { CXM_TUNER_TV_SYSTEM_I, cxm_none_system_code_style },
363 { { 450000, { 0x8e, 0x30 } },
364 { 170000, { 0x8e, 0x90 } },
365 { 45750, { 0x8e, 0xa0 } } },
370 { CXM_TUNER_TV_SYSTEM_I, cxm_none_system_code_style },
372 { { 450000, { 0xce, 0x30 } },
373 { 170000, { 0xce, 0x90 } },
374 { 45750, { 0xce, 0xa0 } } },
376 { 87500, { 0x88, 0xa5 } },
379 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
381 { { 454000, { 0x8e, 0x30 } },
382 { 169000, { 0x8e, 0x90 } },
383 { 48250, { 0x8e, 0xa0 } } },
388 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
390 { { 464000, { 0x8e, 0x30 } },
391 { 141000, { 0x8e, 0x90 } },
392 { 48250, { 0x8e, 0xa0 } } },
394 { 87500, { 0x88, 0xa5 } },
397 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
399 { { 453000, { 0x8e, 0x30 } },
400 { 158000, { 0x8e, 0x90 } },
401 { 55250, { 0x8e, 0xa0 } } },
404 &us_cable_channels },
406 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
408 { { 453000, { 0x8e, 0x30 } },
409 { 158000, { 0x8e, 0x90 } },
410 { 55250, { 0x8e, 0xa0 } } },
412 { 75900, { 0x88, 0xa5 } },
413 &us_cable_channels },
415 { CXM_TUNER_TV_SYSTEM_I, cxm_none_system_code_style },
417 { { 454000, { 0x8e, 0x30 } },
418 { 169000, { 0x8e, 0x90 } },
419 { 45750, { 0x8e, 0xa0 } } },
423 { "LG Innotek TPI8PSB11D",
424 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
426 { { 450000, { 0x8e, 0x30 } },
427 { 170000, { 0x8e, 0x90 } },
428 { 48250, { 0x8e, 0xa0 } } },
432 { "LG Innotek TPI8PSB01N",
433 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
435 { { 450000, { 0x8e, 0x30 } },
436 { 170000, { 0x8e, 0x90 } },
437 { 48250, { 0x8e, 0xa0 } } },
439 { 87500, { 0x88, 0xa5 } },
441 { "LG Innotek TAPC-H701F",
442 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
444 { { 450000, { 0xce, 0x08 } },
445 { 165000, { 0xce, 0x02 } },
446 { 55250, { 0xce, 0x01 } } },
449 &us_cable_channels },
450 { "LG Innotek TAPC-H001F",
451 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
453 { { 450000, { 0xce, 0x08 } },
454 { 165000, { 0xce, 0x02 } },
455 { 55250, { 0xce, 0x01 } } },
457 { 76000, { 0x88, 0x04 } },
458 &us_cable_channels },
459 { "LG Innotek TAPE-H001F",
460 { CXM_TUNER_TV_SYSTEM_MN,
461 cxm_if_system_with_aux_code_style,
462 { { CXM_TUNER_TV_SYSTEM_MN, { 0x16, 0x30, 0x44, 0x30 }},
463 { CXM_TUNER_FM_SYSTEM, { 0x0a, 0x90, 0x20, 0x30 }}
466 { { 442000, { 0xce, 0x04 } },
467 { 160000, { 0xce, 0x02 } },
468 { 48250, { 0xce, 0x01 } } },
470 { 88000, { 0x88, 0x19 } },
471 &us_cable_channels },
472 { "Microtune 4049 FM5",
473 { CXM_TUNER_TV_SYSTEM_BG | CXM_TUNER_TV_SYSTEM_DK
474 | CXM_TUNER_TV_SYSTEM_I
475 | CXM_TUNER_TV_SYSTEM_L | CXM_TUNER_TV_SYSTEM_L_PRIME,
476 cxm_if_system_code_style,
477 { { CXM_TUNER_TV_SYSTEM_BG, { 0xd4, 0x70, 0x09 } },
478 { CXM_TUNER_TV_SYSTEM_DK, { 0xd4, 0x70, 0x0b } },
479 { CXM_TUNER_TV_SYSTEM_I, { 0xd4, 0x70, 0x0a } },
480 { CXM_TUNER_TV_SYSTEM_L, { 0xc4, 0x10, 0x0b } },
481 { CXM_TUNER_TV_SYSTEM_L_PRIME, { 0x84, 0x10, 0x13 } },
482 { CXM_TUNER_FM_SYSTEM, { 0xdc, 0x10, 0x1d } } } },
484 { { 464000, { 0x8e, 0x30 } },
485 { 141000, { 0x8e, 0x90 } },
486 { 45750, { 0x8e, 0xa0 } } },
488 { 87500, { 0x88, 0xa4 } },
491 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
493 { { 446000, { 0x8e, 0x08 } },
494 { 170000, { 0x8e, 0x02 } },
495 { 55250, { 0x8e, 0x01 } } },
498 &us_cable_channels },
502 /* Read from the tuner registers */
504 cxm_tuner_read(device_t iicbus, int i2c_addr, char *buf, int len)
508 if (iicbus_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
511 if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
524 /* Write to the tuner registers */
526 cxm_tuner_write(device_t iicbus, int i2c_addr, const char *buf, int len)
530 if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
533 if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0)
547 cxm_tuner_init(struct cxm_softc *sc)
549 unsigned char status;
552 if (cxm_eeprom_init(sc) < 0)
555 tuner_type = cxm_eeprom_tuner_type(sc);
557 if (tuner_type < 0 || tuner_type >= NUM_ELEMENTS(cxm_tuners))
560 sc->tuner = &cxm_tuners[tuner_type];
561 sc->tuner_channels = sc->tuner->default_channels;
564 if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status))
568 if (cxm_tuner_select_channel(sc, 4) < 0)
571 device_printf(sc->dev, "%s tuner\n", sc->tuner->name);
578 cxm_tuner_select_channel_set(struct cxm_softc *sc, unsigned int channel_set)
583 sc->tuner_channels = sc->tuner->default_channels;
587 for (i = 0; i < NUM_ELEMENTS(channel_sets); i++)
588 if (channel_sets[i]->chnlset == channel_set)
591 if (i >= NUM_ELEMENTS(channel_sets))
594 if (!(sc->tuner->systems.supported & channel_sets[i]->system))
597 sc->tuner_channels = channel_sets[i];
604 cxm_tuner_selected_channel_set(struct cxm_softc *sc)
606 return sc->tuner_channels->chnlset;
611 cxm_tuner_select_frequency(struct cxm_softc *sc,
612 enum cxm_tuner_freq_type freq_type,
615 unsigned char msg[5];
620 unsigned int tuner_msg_len;
622 unsigned long osc_freq;
623 const struct cxm_tuner_band_code *band_code;
624 const struct cxm_tuner_system_code *system_code;
634 if (sc->tuner->systems.code_style != cxm_none_system_code_style) {
635 system = freq_type == cxm_tuner_fm_freq_type
636 ? CXM_TUNER_FM_SYSTEM : sc->tuner_channels->system;
638 for (i = 0; i < NUM_ELEMENTS (sc->tuner->systems.codes); i++)
639 if (sc->tuner->systems.codes[i].system & system)
642 if (i >= NUM_ELEMENTS (sc->tuner->systems.codes))
645 switch (sc->tuner->systems.code_style) {
646 case cxm_port_system_code_style:
647 pb = sc->tuner->systems.codes[i].codes[0];
650 case cxm_if_system_with_aux_code_style:
651 aux = sc->tuner->systems.codes[i].codes[3];
656 case cxm_if_system_code_style:
657 system_code = &sc->tuner->systems.codes[i];
666 case cxm_tuner_fm_freq_type:
668 if (freq < sc->tuner->fm_min_freq
669 || freq > sc->tuner->fm_max_freq
670 || !sc->tuner->fm_band_code.freq)
674 * The Philips FM1216ME MK3 data sheet recommends
675 * first setting the tuner to TV mode at a high
676 * frequency (e.g. 150 MHz), then selecting the
677 * desired FM station in order to ensure that the
678 * tuning voltage does not stay locked at 0V.
681 if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
686 * N = { fRF(pc) + fIF(pc) } / step_size
688 * fRF = RF frequency in MHz
689 * fIF = Intermediate frequency in MHz (FM = 10.70 MHz)
690 * step_size = Step size in MHz (FM = 50 kHz)
693 osc_freq = freq + 10700;
695 N = (20 * osc_freq) / 1000;
697 msg[0] = (unsigned char)(N >> 8);
698 msg[1] = (unsigned char)N;
699 msg[2] = sc->tuner->fm_band_code.codes[0];
700 msg[3] = sc->tuner->fm_band_code.codes[1] | pb;
704 case cxm_tuner_tv_freq_type:
706 if (freq < sc->tuner->min_freq
707 || freq > sc->tuner->max_freq)
711 * N = 16 * { fRF(pc) + fIF(pc) }
713 * fRF = RF frequency in MHz
714 * fIF = Intermediate frequency in MHz
716 * The data sheet doesn't state it, however
717 * this is probably the same equation as
718 * FM simply with 62.5 kHz as the step size.
721 osc_freq = freq + sc->tuner_channels->if_freq;
723 N = (16 * osc_freq) / 1000;
725 for (band_code = sc->tuner->band_codes;
726 band_code->freq > freq; band_code++)
729 if (freq >= sc->tuner_freq) {
730 msg[0] = (unsigned char)(N >> 8);
731 msg[1] = (unsigned char)N;
732 msg[2] = band_code->codes[0];
733 msg[3] = band_code->codes[1] | pb;
735 msg[0] = band_code->codes[0];
736 msg[1] = band_code->codes[1] | pb;
737 msg[2] = (unsigned char)(N >> 8);
738 msg[3] = (unsigned char)N;
750 if (cxm_tuner_write(sc->iicbus, CXM_I2C_TUNER, msg, tuner_msg_len)
755 * Program the IF processing after the tuner since some tuners
756 * use the control byte to set the address of the IF.
761 msg[1] = system_code->codes[0];
762 msg[2] = system_code->codes[1];
763 msg[3] = system_code->codes[2];
765 if (cxm_tuner_write(sc->iicbus, CXM_I2C_TUNER_IF, msg, 4) != 4)
769 sc->tuner_freq = freq;
776 cxm_tuner_select_channel(struct cxm_softc *sc, unsigned int channel)
779 const struct cxm_tuner_channel_assignment *assignments;
780 const struct cxm_tuner_channels *channels;
782 channels = sc->tuner_channels;
785 || channel < channels->min_channel
786 || channel > channels->max_channel)
789 for (assignments = channels->assignments;
790 assignments->channel > channel; assignments++)
793 if (!assignments->freq)
796 freq = assignments->freq
797 + (channel - assignments->channel) * assignments->step;
799 return cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, freq);
804 cxm_tuner_apply_afc(struct cxm_softc *sc)
809 unsigned long max_offset;
810 unsigned long original_freq;
811 unsigned long prev_freq;
812 unsigned long step_size;
814 if (cxm_tuner_wait_for_lock(sc) != 1)
817 original_freq = sc->tuner_freq;
819 freq = sc->tuner_freq;
824 for (i = 0; i < (max_offset / step_size); i++) {
825 status = cxm_tuner_status(sc);
830 if (!(status & CXM_TUNER_PHASE_LOCKED))
833 switch (status & CXM_TUNER_AFC_MASK) {
834 case CXM_TUNER_AFC_FREQ_CENTERED:
837 case CXM_TUNER_AFC_FREQ_MINUS_125:
838 case CXM_TUNER_AFC_FREQ_MINUS_62:
842 case CXM_TUNER_AFC_FREQ_PLUS_62:
843 case CXM_TUNER_AFC_FREQ_PLUS_125:
851 if (freq == prev_freq)
853 prev_freq = sc->tuner_freq;
855 if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
860 * Delay long enough for the tuner to update its status.
863 tsleep(&sc->iicbus, 0, "afc", hz / 10);
867 cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, original_freq);
873 cxm_tuner_is_locked(struct cxm_softc *sc)
877 status = cxm_tuner_status(sc);
882 return (status & CXM_TUNER_PHASE_LOCKED) ? 1 : 0;
887 cxm_tuner_wait_for_lock(struct cxm_softc *sc)
892 * The data sheet states the maximum lock-in time
893 * is 150 ms using fast tuning ... unfortunately
894 * it doesn't state the maximum lock-in time using
895 * moderate tuning. Hopefully 300 ms is enough.
898 for (i = 0; i < 3; i++) {
901 * The frequency may have just changed (prior to
902 * cxm_tuner_wait_for_lock) so start with the delay
903 * to give the tuner a chance to update its status.
906 tsleep(&sc->iicbus, 0, "tuner", hz / 10);
908 switch (cxm_tuner_is_locked(sc)) {
920 device_printf(sc->dev, "tuner failed to lock\n");
926 static const unsigned char afcmap[16] = {
927 CXM_TUNER_AFC_FREQ_CENTERED,
928 CXM_TUNER_AFC_FREQ_MINUS_62,
929 CXM_TUNER_AFC_FREQ_MINUS_62,
930 CXM_TUNER_AFC_FREQ_MINUS_62,
931 CXM_TUNER_AFC_FREQ_MINUS_125,
932 CXM_TUNER_AFC_FREQ_MINUS_125,
933 CXM_TUNER_AFC_FREQ_MINUS_125,
934 CXM_TUNER_AFC_FREQ_MINUS_125,
935 CXM_TUNER_AFC_FREQ_PLUS_125,
936 CXM_TUNER_AFC_FREQ_PLUS_125,
937 CXM_TUNER_AFC_FREQ_PLUS_125,
938 CXM_TUNER_AFC_FREQ_PLUS_125,
939 CXM_TUNER_AFC_FREQ_PLUS_62,
940 CXM_TUNER_AFC_FREQ_PLUS_62,
941 CXM_TUNER_AFC_FREQ_PLUS_62,
942 CXM_TUNER_AFC_FREQ_CENTERED
946 cxm_tuner_status(struct cxm_softc *sc)
948 unsigned char status;
950 if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status))
954 if (sc->tuner->systems.code_style == cxm_if_system_code_style
955 || sc->tuner->systems.code_style
956 == cxm_if_system_with_aux_code_style) {
957 unsigned char if_status;
959 if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER_IF,
960 &if_status, sizeof(if_status))
961 != sizeof(if_status))
964 status &= ~CXM_TUNER_AFC_MASK;
965 status |= afcmap[(if_status >> 1) & 0x0f];