The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/video/cxm/cxm_tuner.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2003, 2004, 2005
    3  *      John Wehle <john@feith.com>.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    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.
   18  *
   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.
   30  */
   31 
   32 /*
   33  * Tuner routines for the Conexant MPEG-2 Codec driver.
   34  *
   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
   38  * wheel.
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/conf.h>
   44 #include <sys/uio.h>
   45 #include <sys/kernel.h>
   46 #include <sys/poll.h>
   47 #include <sys/select.h>
   48 #include <sys/resource.h>
   49 #include <sys/bus.h>
   50 #include <sys/rman.h>
   51 
   52 #include <machine/clock.h>
   53 
   54 #include <dev/video/meteor/ioctl_meteor.h>
   55 #include <dev/video/bktr/ioctl_bt848.h>
   56 
   57 #include <dev/video/cxm/cxm.h>
   58 
   59 #include <bus/iicbus/iiconf.h>
   60 #include <bus/iicbus/iicbus.h>
   61 
   62 #include "iicbb_if.h"
   63 
   64 
   65 /*
   66  * Channel mappings derived from
   67  * http://developer.apple.com/technotes/tn/tn1012.html
   68  *
   69  * B/G Cable mapping based the bktr Western European mapping
   70  */
   71 
   72 static const struct cxm_tuner_channels
   73 us_air_channels = {
   74         "US Broadcast",
   75         CHNLSET_NABCST,
   76         CXM_TUNER_TV_SYSTEM_MN,
   77         2,
   78         69,
   79         45750,
   80         { { 14, 471250, 6000 },
   81           { 7, 175250, 6000 },
   82           { 5, 77250, 6000 },
   83           { 2, 55250, 6000 } }
   84 };
   85 
   86 static const struct cxm_tuner_channels
   87 us_cable_channels = {
   88         "US Cable",
   89         CHNLSET_CABLEIRC,
   90         CXM_TUNER_TV_SYSTEM_MN,
   91         1,
   92         125,
   93         45750,
   94         { { 100, 649250, 6000 },
   95           { 95, 91250, 6000 },
   96           { 23, 217250, 6000 },
   97           { 14, 121250, 6000 },
   98           { 7, 175250, 6000 },
   99           { 5, 77250, 6000 },
  100           { 2, 55250, 6000 },
  101           { 1, 73250, 6000 } }
  102 };
  103 
  104 static const struct cxm_tuner_channels
  105 bg_air_channels = {
  106         "B/G Broadcast",
  107         0,
  108         CXM_TUNER_TV_SYSTEM_BG,
  109         2,
  110         89,
  111         38900,
  112         { { 82, 175250, 7000 },
  113           { 80, 55250, 7000 },
  114           { 79, 217250, 7000 },
  115           { 77, 209250, 7000 },
  116           { 76, 138250, 9000 },
  117           { 75, 102250, 9000 },
  118           { 73, 86250, 9000 },
  119           { 72, 64250, 7500 },
  120           { 70, 49750, 7500 },
  121           { 21, 471250, 8000 },
  122           { 20, 210250, 8500 },
  123           { 18, 192750, 8500 },
  124           { 16, 175250, 8000 },
  125           { 15, 82250, 8500 },
  126           { 13, 53750, 8500 },
  127           { 5, 175250, 7000 },
  128           { 2, 48250, 7000 } }
  129 };
  130 
  131 static const struct cxm_tuner_channels
  132 bg_cable_channels = {
  133         "B/G Cable",
  134         CHNLSET_WEUROPE,
  135         CXM_TUNER_TV_SYSTEM_BG,
  136         2,
  137         120,
  138         38900,
  139         { { 100, 303250, 8000 },
  140           { 90, 231250, 7000 },
  141           { 80, 105250, 7000 },
  142           { 79, 0, 0 },
  143           { 78, 0, 0 },
  144           { 77, 0, 0 },
  145           { 74, 69250, 7000 },
  146           { 73, 0, 0 },
  147           { 70, 45750, 8000 },
  148           { 21, 471250, 8000 },
  149           { 20, 210250, 8500 },
  150           { 18, 192750, 8500 },
  151           { 16, 175250, 8000 },
  152           { 15, 82250, 8500 },
  153           { 13, 53750, 8500 },
  154           { 5, 175250, 7000 },
  155           { 2, 48250, 7000 } }
  156 };
  157 
  158 static const struct cxm_tuner_channels
  159 bg_australia_channels = {
  160         "B/G Australia",
  161         CHNLSET_AUSTRALIA,
  162         CXM_TUNER_TV_SYSTEM_BG,
  163         1,
  164         83,
  165         38900,
  166         { { 28, 527250, 7000 },
  167           { 10, 209250, 7000 },
  168           { 6, 175250, 7000 },
  169           { 4, 95250, 7000 },
  170           { 3, 86250, 7000 },
  171           { 1, 57250, 7000 } }
  172 };
  173 
  174 static const struct cxm_tuner_channels
  175 i_air_channels = {
  176         "I Broadcast",
  177         0,
  178         CXM_TUNER_TV_SYSTEM_I,
  179         1,
  180         83,
  181         38900,
  182         { { 75, 179750, 5000 },
  183           { 71, 51750, 5000 },
  184           { 70, 45000, 5000 },
  185           { 21, 471250, 8000 },
  186           { 20, 0, 0 },
  187           { 19, 0, 0 },
  188           { 18, 0, 0 },
  189           { 17, 0, 0 },
  190           { 16, 0, 0 },
  191           { 15, 0, 0 },
  192           { 14, 0, 0 },
  193           { 13, 247250, 8000 },
  194           { 12, 0, 0 },
  195           { 4, 175250, 8000 },
  196           { 1, 45750, 8000 } }
  197 };
  198 
  199 static const struct cxm_tuner_channels
  200 l_air_channels = {
  201         "L Broadcast",
  202         CHNLSET_FRANCE,
  203         CXM_TUNER_TV_SYSTEM_L,
  204         1,
  205         69,
  206         38900,
  207         { { 21, 471250, 8000 },
  208           { 20, 0, 0 },
  209           { 19, 0, 0 },
  210           { 18, 0, 0 },
  211           { 17, 0, 0 },
  212           { 16, 0, 0 },
  213           { 15, 0, 0 },
  214           { 14, 0, 0 },
  215           { 8, 176000, 8000 },
  216           { 5, 57250, 3250 },
  217           { 4, 55750, 1500 },
  218           { 3, 54000, 1750 },
  219           { 2, 49250, 4750 },
  220           { 1, 47750, 1500 } }
  221 };
  222 
  223 static const struct cxm_tuner_channels
  224 japan_air_channels = {
  225         "Japan Broadcast",
  226         CHNLSET_JPNBCST,
  227         CXM_TUNER_TV_SYSTEM_MN,
  228         1,
  229         62,
  230         45750,
  231         { { 13, 471250, 6000 },
  232           { 8, 193250, 6000 },
  233           { 4, 171250, 6000 },
  234           { 1, 91250, 6000 } }
  235 };
  236 
  237 static const struct cxm_tuner_channels
  238 japan_cable_channels = {
  239         "Japan Cable",
  240         CHNLSET_JPNCABLE,
  241         CXM_TUNER_TV_SYSTEM_MN,
  242         1,
  243         63,
  244         45750,
  245         { { 23, 223250, 6000 },
  246           { 22, 165250, 6000 },
  247           { 13, 109250, 6000 },
  248           { 8, 193250, 6000 },
  249           { 4, 171250, 6000 },
  250           { 1, 91250, 6000 } }
  251 };
  252 
  253 
  254 static const struct cxm_tuner_channels
  255 *channel_sets[] = {
  256         &us_air_channels,
  257         &us_cable_channels,
  258         &bg_air_channels,
  259         &bg_cable_channels,
  260         &bg_australia_channels,
  261         &i_air_channels,
  262         &l_air_channels,
  263         &japan_air_channels,
  264         &japan_cable_channels
  265 };
  266 
  267 
  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 },
  272                 48250, 855250,
  273                 { { 450000, { 0x8e, 0x30 } },
  274                   { 170000, { 0x8e, 0x90 } },
  275                   { 48250, { 0x8e, 0xa0 } } },
  276                 0, 0,
  277                 { 0 },
  278                 &bg_air_channels },
  279         { "Philips FM1216",
  280                 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
  281                 48250, 855250,
  282                 { { 450000, { 0xce, 0x30 } },
  283                   { 170000, { 0xce, 0x90 } },
  284                   { 48250, { 0xce, 0xa0 } } },
  285                 87500, 108000,
  286                 { 87500, { 0x88, 0xa5 } },
  287                 &bg_air_channels },
  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 } } } },
  298                 48250, 855250,
  299                 { { 450000, { 0x8e, 0x30 } },
  300                   { 170000, { 0x8e, 0x90 } },
  301                   { 48250, { 0x8e, 0xa0 } } },
  302                 0, 0,
  303                 { 0 },
  304                 &l_air_channels },
  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 }}
  315                     } },
  316                 48250, 863250,
  317                 { { 442000, { 0xce, 0x04 } },
  318                   { 160000, { 0xce, 0x02 } },
  319                   { 48250, { 0xce, 0x01 } } },
  320                 0, 0,
  321                 { 0 },
  322                 &l_air_channels },
  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 }}
  334                     } },
  335                 48250, 863250,
  336                 { { 442000, { 0xce, 0x04 } },
  337                   { 160000, { 0xce, 0x02 } },
  338                   { 48250, { 0xce, 0x01 } } },
  339                 87500, 108000,
  340                 { 87500, { 0x88, 0x19 } },
  341                 &l_air_channels },
  342         { "Philips FI1236 MK2",
  343                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  344                 55250, 801250,
  345                 { { 454000, { 0x8e, 0x30 } },
  346                   { 160000, { 0x8e, 0x90 } },
  347                   { 55250, { 0x8e, 0xa0 } } },
  348                 0, 0,
  349                 { 0 },
  350                 &us_cable_channels },
  351         { "Philips FM1236",
  352                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  353                 55250, 801250,
  354                 { { 454000, { 0xce, 0x30 } },
  355                   { 160000, { 0xce, 0x90 } },
  356                   { 55250, { 0xce, 0xa0 } } },
  357                 76000, 108000,
  358                 { 76000, { 0x88, 0xa5 } },
  359                 &us_cable_channels },
  360         { "Philips FI1246 MK2",
  361                 { CXM_TUNER_TV_SYSTEM_I, cxm_none_system_code_style },
  362                 45750, 855250,
  363                 { { 450000, { 0x8e, 0x30 } },
  364                   { 170000, { 0x8e, 0x90 } },
  365                   { 45750, { 0x8e, 0xa0 } } },
  366                 0, 0,
  367                 { 0 },
  368                 &i_air_channels },
  369         { "Philips FM1246",
  370                 { CXM_TUNER_TV_SYSTEM_I, cxm_none_system_code_style },
  371                 45750, 855250,
  372                 { { 450000, { 0xce, 0x30 } },
  373                   { 170000, { 0xce, 0x90 } },
  374                   { 45750, { 0xce, 0xa0 } } },
  375                 87500, 108000,
  376                 { 87500, { 0x88, 0xa5 } },
  377                 &i_air_channels },
  378         { "Temic 4006 FH5",
  379                 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
  380                 48250, 855250,
  381                 { { 454000, { 0x8e, 0x30 } },
  382                   { 169000, { 0x8e, 0x90 } },
  383                   { 48250, { 0x8e, 0xa0 } } },
  384                 0, 0,
  385                 { 0 },
  386                 &bg_air_channels },
  387         { "Temic 4009 FR5",
  388                 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
  389                 48250, 855250,
  390                 { { 464000, { 0x8e, 0x30 } },
  391                   { 141000, { 0x8e, 0x90 } },
  392                   { 48250, { 0x8e, 0xa0 } } },
  393                 87500, 108100,
  394                 { 87500, { 0x88, 0xa5 } },
  395                 &bg_air_channels },
  396         { "Temic 4036 FY5",
  397                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  398                 55250, 801250,
  399                 { { 453000, { 0x8e, 0x30 } },
  400                   { 158000, { 0x8e, 0x90 } },
  401                   { 55250, { 0x8e, 0xa0 } } },
  402                 0, 0,
  403                 { 0 },
  404                 &us_cable_channels },
  405         { "Temic 4039 FR5",
  406                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  407                 55250, 801250,
  408                 { { 453000, { 0x8e, 0x30 } },
  409                   { 158000, { 0x8e, 0x90 } },
  410                   { 55250, { 0x8e, 0xa0 } } },
  411                 75900, 108100,
  412                 { 75900, { 0x88, 0xa5 } },
  413                 &us_cable_channels },
  414         { "Temic 4066 FY5",
  415                 { CXM_TUNER_TV_SYSTEM_I, cxm_none_system_code_style },
  416                 45750, 855250,
  417                 { { 454000, { 0x8e, 0x30 } },
  418                   { 169000, { 0x8e, 0x90 } },
  419                   { 45750, { 0x8e, 0xa0 } } },
  420                 0, 0,
  421                 { 0 },
  422                 &i_air_channels },
  423         { "LG Innotek TPI8PSB11D",
  424                 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
  425                 48250, 855250,
  426                 { { 450000, { 0x8e, 0x30 } },
  427                   { 170000, { 0x8e, 0x90 } },
  428                   { 48250, { 0x8e, 0xa0 } } },
  429                 0, 0,
  430                 { 0 },
  431                 &bg_air_channels },
  432         { "LG Innotek TPI8PSB01N",
  433                 { CXM_TUNER_TV_SYSTEM_BG, cxm_none_system_code_style },
  434                 48250, 855250,
  435                 { { 450000, { 0x8e, 0x30 } },
  436                   { 170000, { 0x8e, 0x90 } },
  437                   { 48250, { 0x8e, 0xa0 } } },
  438                 87500, 108000,
  439                 { 87500, { 0x88, 0xa5 } },
  440                 &bg_air_channels },
  441         { "LG Innotek TAPC-H701F",
  442                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  443                 55250, 801250,
  444                 { { 450000, { 0xce, 0x08 } },
  445                   { 165000, { 0xce, 0x02 } },
  446                   { 55250, { 0xce, 0x01 } } },
  447                 0, 0,
  448                 { 0 },
  449                 &us_cable_channels },
  450         { "LG Innotek TAPC-H001F",
  451                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  452                 55250, 801250,
  453                 { { 450000, { 0xce, 0x08 } },
  454                   { 165000, { 0xce, 0x02 } },
  455                   { 55250, { 0xce, 0x01 } } },
  456                 76000, 108000,
  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 }}
  464                     } },
  465                 48250, 801250,
  466                 { { 442000, { 0xce, 0x04 } },
  467                   { 160000, { 0xce, 0x02 } },
  468                   { 48250, { 0xce, 0x01 } } },
  469                 88000, 108000,
  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 } } } },
  483                 45750, 855250,
  484                 { { 464000, { 0x8e, 0x30 } },
  485                   { 141000, { 0x8e, 0x90 } },
  486                   { 45750, { 0x8e, 0xa0 } } },
  487                 87500, 108100,
  488                 { 87500, { 0x88, 0xa4 } },
  489                 &l_air_channels },
  490         { "TCL 2002N-6A",
  491                 { CXM_TUNER_TV_SYSTEM_MN, cxm_none_system_code_style },
  492                 55250, 801250,
  493                 { { 446000, { 0x8e, 0x08 } },
  494                   { 170000, { 0x8e, 0x02 } },
  495                   { 55250, { 0x8e, 0x01 } } },
  496                 0, 0,
  497                 { 0 },
  498                 &us_cable_channels },
  499 };
  500 
  501 
  502 /* Read from the tuner registers */
  503 static int
  504 cxm_tuner_read(device_t iicbus, int i2c_addr, char *buf, int len)
  505 {
  506         int received;
  507 
  508         if (iicbus_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
  509                 return -1;
  510 
  511         if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
  512                 goto fail;
  513 
  514         iicbus_stop(iicbus);
  515 
  516         return received;
  517 
  518 fail:
  519         iicbus_stop(iicbus);
  520         return -1;
  521 }
  522 
  523 
  524 /* Write to the tuner registers */
  525 static int
  526 cxm_tuner_write(device_t iicbus, int i2c_addr, const char *buf, int len)
  527 {
  528         int sent;
  529 
  530         if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
  531                 return -1;
  532 
  533         if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0)
  534                 goto fail;
  535 
  536         iicbus_stop(iicbus);
  537 
  538         return sent;
  539 
  540 fail:
  541         iicbus_stop(iicbus);
  542         return -1;
  543 }
  544 
  545 
  546 int
  547 cxm_tuner_init(struct cxm_softc *sc)
  548 {
  549         unsigned char status;
  550         int tuner_type;
  551 
  552         if (cxm_eeprom_init(sc) < 0)
  553                 return -1;
  554 
  555         tuner_type = cxm_eeprom_tuner_type(sc);
  556 
  557         if (tuner_type < 0 || tuner_type >= NUM_ELEMENTS(cxm_tuners))
  558                 return -1;
  559 
  560         sc->tuner = &cxm_tuners[tuner_type];
  561         sc->tuner_channels = sc->tuner->default_channels;
  562         sc->tuner_freq = 0;
  563 
  564         if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status))
  565             != sizeof(status))
  566                 return -1;
  567 
  568         if (cxm_tuner_select_channel(sc, 4) < 0)
  569                 return -1;
  570 
  571         device_printf(sc->dev, "%s tuner\n", sc->tuner->name);
  572 
  573         return 0;
  574 }
  575 
  576 
  577 int
  578 cxm_tuner_select_channel_set(struct cxm_softc *sc, unsigned int channel_set)
  579 {
  580         unsigned int i;
  581 
  582         if (!channel_set) {
  583                 sc->tuner_channels = sc->tuner->default_channels;
  584                 return 0;
  585         }
  586 
  587         for (i = 0; i < NUM_ELEMENTS(channel_sets); i++)
  588                 if (channel_sets[i]->chnlset == channel_set)
  589                         break;
  590 
  591         if (i >= NUM_ELEMENTS(channel_sets))
  592                 return -1;
  593 
  594         if (!(sc->tuner->systems.supported & channel_sets[i]->system))
  595                 return -1;
  596 
  597         sc->tuner_channels = channel_sets[i];
  598 
  599         return 0;
  600 }
  601 
  602 
  603 unsigned int
  604 cxm_tuner_selected_channel_set(struct cxm_softc *sc)
  605 {
  606         return sc->tuner_channels->chnlset;
  607 }
  608 
  609 
  610 int
  611 cxm_tuner_select_frequency(struct cxm_softc *sc,
  612                             enum cxm_tuner_freq_type freq_type,
  613                             unsigned long freq)
  614 {
  615         unsigned char msg[5];
  616         unsigned char aux;
  617         unsigned char pb;
  618         unsigned int i;
  619         unsigned int system;
  620         unsigned int tuner_msg_len;
  621         unsigned long N;
  622         unsigned long osc_freq;
  623         const struct cxm_tuner_band_code *band_code;
  624         const struct cxm_tuner_system_code *system_code;
  625 
  626         N = 0;
  627         aux = 0;
  628         pb = 0;
  629 
  630         system_code = NULL;
  631 
  632         tuner_msg_len = 4;
  633 
  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;
  637 
  638                 for (i = 0; i < NUM_ELEMENTS (sc->tuner->systems.codes); i++)
  639                         if (sc->tuner->systems.codes[i].system & system)
  640                                 break;
  641 
  642                 if (i >= NUM_ELEMENTS (sc->tuner->systems.codes))
  643                         return -1;
  644 
  645                 switch (sc->tuner->systems.code_style) {
  646                 case cxm_port_system_code_style:
  647                         pb = sc->tuner->systems.codes[i].codes[0];
  648                         break;
  649 
  650                 case cxm_if_system_with_aux_code_style:
  651                         aux = sc->tuner->systems.codes[i].codes[3];
  652                         tuner_msg_len = 5;
  653 
  654                         /* FALLTHROUGH */
  655 
  656                 case cxm_if_system_code_style:
  657                         system_code = &sc->tuner->systems.codes[i];
  658                         break;
  659 
  660                 default:
  661                         return -1;
  662                 }
  663         }
  664 
  665         switch (freq_type) {
  666         case cxm_tuner_fm_freq_type:
  667 
  668                 if (freq < sc->tuner->fm_min_freq
  669                     || freq > sc->tuner->fm_max_freq
  670                     || !sc->tuner->fm_band_code.freq)
  671                         return -1;
  672 
  673                 /*
  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.
  679                  */
  680 
  681                 if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
  682                                                150000) < 0)
  683                         return -1;
  684 
  685                 /*
  686                  * N = { fRF(pc) + fIF(pc) } / step_size
  687                  *
  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)
  691                  */
  692 
  693                 osc_freq = freq + 10700;
  694 
  695                 N = (20 * osc_freq) / 1000;
  696 
  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;
  701                 msg[4] = aux;
  702                 break;
  703 
  704         case cxm_tuner_tv_freq_type:
  705 
  706                 if (freq < sc->tuner->min_freq
  707                     || freq > sc->tuner->max_freq)
  708                         return -1;
  709 
  710                 /*
  711                  * N = 16 * { fRF(pc) + fIF(pc) }
  712                  *
  713                  * fRF = RF frequency in MHz
  714                  * fIF = Intermediate frequency in MHz
  715                  *
  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.
  719                  */
  720 
  721                 osc_freq = freq + sc->tuner_channels->if_freq;
  722 
  723                 N = (16 * osc_freq) / 1000;
  724 
  725                 for (band_code = sc->tuner->band_codes;
  726                      band_code->freq > freq; band_code++)
  727                         ;
  728 
  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;
  734                 } else {
  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;
  739                 }
  740                 msg[4] = aux;
  741                 break;
  742 
  743         default:
  744                 return -1;
  745         }
  746 
  747         if (N > 32767)
  748                 return -1;
  749 
  750         if (cxm_tuner_write(sc->iicbus, CXM_I2C_TUNER, msg, tuner_msg_len)
  751                             != tuner_msg_len)
  752                 return -1;
  753 
  754         /*
  755          * Program the IF processing after the tuner since some tuners
  756          * use the control byte to set the address of the IF.
  757          */
  758 
  759         if (system_code) {
  760                 msg[0] = 0x00;
  761                 msg[1] = system_code->codes[0];
  762                 msg[2] = system_code->codes[1];
  763                 msg[3] = system_code->codes[2];
  764 
  765                 if (cxm_tuner_write(sc->iicbus, CXM_I2C_TUNER_IF, msg, 4) != 4)
  766                         return -1;
  767         }
  768 
  769         sc->tuner_freq = freq;
  770 
  771         return 0;
  772 }
  773 
  774 
  775 int
  776 cxm_tuner_select_channel(struct cxm_softc *sc, unsigned int channel)
  777 {
  778         unsigned long freq;
  779         const struct cxm_tuner_channel_assignment *assignments;
  780         const struct cxm_tuner_channels *channels;
  781 
  782         channels = sc->tuner_channels;
  783 
  784         if (!channels
  785             || channel < channels->min_channel
  786             || channel > channels->max_channel)
  787                 return -1;
  788 
  789         for (assignments = channels->assignments;
  790              assignments->channel > channel; assignments++)
  791                 ;
  792 
  793         if (!assignments->freq)
  794                 return -1;
  795 
  796         freq = assignments->freq
  797                + (channel - assignments->channel) * assignments->step;
  798 
  799         return cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, freq);
  800 }
  801 
  802 
  803 int
  804 cxm_tuner_apply_afc(struct cxm_softc *sc)
  805 {
  806         unsigned int i;
  807         int status;
  808         unsigned long freq;
  809         unsigned long max_offset;
  810         unsigned long original_freq;
  811         unsigned long prev_freq;
  812         unsigned long step_size;
  813 
  814         if (cxm_tuner_wait_for_lock(sc) != 1)
  815                 return -1;
  816 
  817         original_freq = sc->tuner_freq;
  818 
  819         freq = sc->tuner_freq;
  820         prev_freq = 0;
  821         max_offset = 2000;
  822         step_size = 63;
  823 
  824         for (i = 0; i < (max_offset / step_size); i++) {
  825                 status = cxm_tuner_status(sc);
  826 
  827                 if (status == -1)
  828                         break;
  829 
  830                 if (!(status & CXM_TUNER_PHASE_LOCKED))
  831                         break;
  832 
  833                 switch (status & CXM_TUNER_AFC_MASK) {
  834                 case CXM_TUNER_AFC_FREQ_CENTERED:
  835                         return 0;
  836 
  837                 case CXM_TUNER_AFC_FREQ_MINUS_125:
  838                 case CXM_TUNER_AFC_FREQ_MINUS_62:
  839                         freq -= step_size;
  840                         break;
  841 
  842                 case CXM_TUNER_AFC_FREQ_PLUS_62:
  843                 case CXM_TUNER_AFC_FREQ_PLUS_125:
  844                         freq += step_size;
  845                         break;
  846 
  847                 default:
  848                         goto fail;
  849                 }
  850 
  851                 if (freq == prev_freq)
  852                         return 0;
  853                 prev_freq = sc->tuner_freq;
  854 
  855                 if (cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type,
  856                                                freq) < 0)
  857                         break;
  858 
  859                 /*
  860                  * Delay long enough for the tuner to update its status.
  861                  */
  862 
  863                 tsleep(&sc->iicbus, 0, "afc", hz / 10);
  864         }
  865 
  866 fail:
  867         cxm_tuner_select_frequency(sc, cxm_tuner_tv_freq_type, original_freq);
  868         return -1;
  869 }
  870 
  871 
  872 int
  873 cxm_tuner_is_locked(struct cxm_softc *sc)
  874 {
  875         int status;
  876 
  877         status = cxm_tuner_status(sc);
  878 
  879         if (status == -1)
  880                 return -1;
  881 
  882         return (status & CXM_TUNER_PHASE_LOCKED) ? 1 : 0;
  883 }
  884 
  885 
  886 int
  887 cxm_tuner_wait_for_lock(struct cxm_softc *sc)
  888 {
  889         unsigned int i;
  890 
  891         /*
  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.
  896          */
  897 
  898         for (i = 0; i < 3; i++) {
  899 
  900                 /*
  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.
  904                  */
  905 
  906                 tsleep(&sc->iicbus, 0, "tuner", hz / 10);
  907 
  908                 switch (cxm_tuner_is_locked(sc)) {
  909                 case 1:
  910                         return 1;
  911 
  912                 case 0:
  913                         break;
  914 
  915                 default:
  916                         return -1;
  917                 }
  918         }
  919 
  920         device_printf(sc->dev, "tuner failed to lock\n");
  921 
  922         return 0;
  923 }
  924 
  925 
  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
  943 };
  944 
  945 int
  946 cxm_tuner_status(struct cxm_softc *sc)
  947 {
  948         unsigned char status;
  949 
  950         if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER, &status, sizeof(status))
  951             != sizeof(status))
  952                 return -1;
  953 
  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;
  958 
  959                 if (cxm_tuner_read(sc->iicbus, CXM_I2C_TUNER_IF,
  960                                    &if_status, sizeof(if_status))
  961                     != sizeof(if_status))
  962                         return -1;
  963 
  964                 status &= ~CXM_TUNER_AFC_MASK;
  965                 status |= afcmap[(if_status >> 1) & 0x0f];
  966         }
  967 
  968         return status;
  969 }

Cache object: aaa8ae46b9ee373e64991c41b090faf0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.