linux/drivers/staging/go7007/wis-sony-tuner.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-2006 Micronas USA Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License (Version 2) as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software Foundation,
  15 * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/init.h>
  20#include <linux/i2c.h>
  21#include <linux/videodev2.h>
  22#include <media/tuner.h>
  23#include <media/v4l2-common.h>
  24#include <media/v4l2-ioctl.h>
  25
  26#include "wis-i2c.h"
  27
  28/* #define MPX_DEBUG */
  29
  30/* AS(IF/MPX) pin:      LOW      HIGH/OPEN
  31 * IF/MPX address:   0x42/0x40   0x43/0x44
  32 */
  33#define IF_I2C_ADDR     0x43
  34#define MPX_I2C_ADDR    0x44
  35
  36static v4l2_std_id force_band;
  37static char force_band_str[] = "-";
  38module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
  39static int force_mpx_mode = -1;
  40module_param(force_mpx_mode, int, 0644);
  41
  42/* Store tuner info in the same format as tuner.c, so maybe we can put the
  43 * Sony tuner support in there. */
  44struct sony_tunertype {
  45        char *name;
  46        unsigned char Vendor; /* unused here */
  47        unsigned char Type; /* unused here */
  48
  49        unsigned short thresh1; /*  band switch VHF_LO <=> VHF_HI */
  50        unsigned short thresh2; /*  band switch VHF_HI <=> UHF */
  51        unsigned char VHF_L;
  52        unsigned char VHF_H;
  53        unsigned char UHF;
  54        unsigned char config;
  55        unsigned short IFPCoff;
  56};
  57
  58/* This array is indexed by (tuner_type - 200) */
  59static struct sony_tunertype sony_tuners[] = {
  60        { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
  61          16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
  62        { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
  63          16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
  64        { "Sony NTSC (BTF-PB463Z)", 0, 0,
  65          16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
  66};
  67
  68struct wis_sony_tuner {
  69        int type;
  70        v4l2_std_id std;
  71        unsigned int freq;
  72        int mpxmode;
  73        u32 audmode;
  74};
  75
  76/* Basically the same as default_set_tv_freq() in tuner.c */
  77static int set_freq(struct i2c_client *client, int freq)
  78{
  79        struct wis_sony_tuner *t = i2c_get_clientdata(client);
  80        char *band_name;
  81        int n;
  82        int band_select;
  83        struct sony_tunertype *tun;
  84        u8 buffer[4];
  85
  86        tun = &sony_tuners[t->type - 200];
  87        if (freq < tun->thresh1) {
  88                band_name = "VHF_L";
  89                band_select = tun->VHF_L;
  90        } else if (freq < tun->thresh2) {
  91                band_name = "VHF_H";
  92                band_select = tun->VHF_H;
  93        } else {
  94                band_name = "UHF";
  95                band_select = tun->UHF;
  96        }
  97        printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n",
  98                        freq / 16, (freq % 16) * 625, band_name);
  99        n = freq + tun->IFPCoff;
 100
 101        buffer[0] = n >> 8;
 102        buffer[1] = n & 0xff;
 103        buffer[2] = tun->config;
 104        buffer[3] = band_select;
 105        i2c_master_send(client, buffer, 4);
 106
 107        return 0;
 108}
 109
 110static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
 111{
 112        u8 buffer[5];
 113        struct i2c_msg msg;
 114
 115        buffer[0] = dev;
 116        buffer[1] = addr >> 8;
 117        buffer[2] = addr & 0xff;
 118        buffer[3] = val >> 8;
 119        buffer[4] = val & 0xff;
 120        msg.addr = MPX_I2C_ADDR;
 121        msg.flags = 0;
 122        msg.len = 5;
 123        msg.buf = buffer;
 124        i2c_transfer(client->adapter, &msg, 1);
 125        return 0;
 126}
 127
 128/*
 129 * MPX register values for the BTF-PG472Z:
 130 *
 131 *                                 FM_     NICAM_  SCART_
 132 *          MODUS  SOURCE    ACB   PRESCAL PRESCAL PRESCAL SYSTEM  VOLUME
 133 *         10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
 134 *         ---------------------------------------------------------------
 135 * Auto     1003    0020    0100    2603    5000    XXXX    0001    7500
 136 *
 137 * B/G
 138 *  Mono    1003    0020    0100    2603    5000    XXXX    0003    7500
 139 *  A2      1003    0020    0100    2601    5000    XXXX    0003    7500
 140 *  NICAM   1003    0120    0100    2603    5000    XXXX    0008    7500
 141 *
 142 * I
 143 *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
 144 *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
 145 *
 146 * D/K
 147 *  Mono    1003    0020    0100    2603    5000    XXXX    0004    7500
 148 *  A2-1    1003    0020    0100    2601    5000    XXXX    0004    7500
 149 *  A2-2    1003    0020    0100    2601    5000    XXXX    0005    7500
 150 *  A2-3    1003    0020    0100    2601    5000    XXXX    0007    7500
 151 *  NICAM   1003    0120    0100    2603    5000    XXXX    000B    7500
 152 *
 153 * L/L'
 154 *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
 155 *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
 156 *
 157 * M
 158 *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
 159 *
 160 * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
 161 *
 162 * Bilingual selection in A2/NICAM:
 163 *
 164 *         High byte of SOURCE     Left chan   Right chan
 165 *                 0x01              MAIN         SUB
 166 *                 0x03              MAIN         MAIN
 167 *                 0x04              SUB          SUB
 168 *
 169 * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
 170 * 0x00 (all other bands).  Force mono in A2 with FMONO_A2:
 171 *
 172 *                      FMONO_A2
 173 *                      10/0022
 174 *                      --------
 175 *     Forced mono ON     07F0
 176 *     Forced mono OFF    0190
 177 */
 178
 179static struct {
 180        enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
 181        u16 modus;
 182        u16 source;
 183        u16 acb;
 184        u16 fm_prescale;
 185        u16 nicam_prescale;
 186        u16 scart_prescale;
 187        u16 system;
 188        u16 volume;
 189} mpx_audio_modes[] = {
 190        /* Auto */      { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 191                                        0x5000, 0x0000, 0x0001, 0x7500 },
 192        /* B/G Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 193                                        0x5000, 0x0000, 0x0003, 0x7500 },
 194        /* B/G A2 */    { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 195                                        0x5000, 0x0000, 0x0003, 0x7500 },
 196        /* B/G NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
 197                                        0x5000, 0x0000, 0x0008, 0x7500 },
 198        /* I Mono */    { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 199                                        0x7900, 0x0000, 0x000A, 0x7500 },
 200        /* I NICAM */   { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
 201                                        0x7900, 0x0000, 0x000A, 0x7500 },
 202        /* D/K Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
 203                                        0x5000, 0x0000, 0x0004, 0x7500 },
 204        /* D/K A2-1 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 205                                        0x5000, 0x0000, 0x0004, 0x7500 },
 206        /* D/K A2-2 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 207                                        0x5000, 0x0000, 0x0005, 0x7500 },
 208        /* D/K A2-3 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
 209                                        0x5000, 0x0000, 0x0007, 0x7500 },
 210        /* D/K NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
 211                                        0x5000, 0x0000, 0x000B, 0x7500 },
 212        /* L/L' Mono */ { AUD_MONO,     0x0003, 0x0200, 0x0100, 0x7C03,
 213                                        0x5000, 0x2200, 0x0009, 0x7500 },
 214        /* L/L' NICAM */{ AUD_NICAM_L,  0x0003, 0x0120, 0x0100, 0x7C03,
 215                                        0x5000, 0x0000, 0x0009, 0x7500 },
 216};
 217
 218#define MPX_NUM_MODES   ARRAY_SIZE(mpx_audio_modes)
 219
 220static int mpx_setup(struct i2c_client *client)
 221{
 222        struct wis_sony_tuner *t = i2c_get_clientdata(client);
 223        u16 source = 0;
 224        u8 buffer[3];
 225        struct i2c_msg msg;
 226
 227        /* reset MPX */
 228        buffer[0] = 0x00;
 229        buffer[1] = 0x80;
 230        buffer[2] = 0x00;
 231        msg.addr = MPX_I2C_ADDR;
 232        msg.flags = 0;
 233        msg.len = 3;
 234        msg.buf = buffer;
 235        i2c_transfer(client->adapter, &msg, 1);
 236        buffer[1] = 0x00;
 237        i2c_transfer(client->adapter, &msg, 1);
 238
 239        if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
 240                switch (t->audmode) {
 241                case V4L2_TUNER_MODE_MONO:
 242                        switch (mpx_audio_modes[t->mpxmode].audio_mode) {
 243                        case AUD_A2:
 244                                source = mpx_audio_modes[t->mpxmode].source;
 245                                break;
 246                        case AUD_NICAM:
 247                                source = 0x0000;
 248                                break;
 249                        case AUD_NICAM_L:
 250                                source = 0x0200;
 251                                break;
 252                        default:
 253                                break;
 254                        }
 255                        break;
 256                case V4L2_TUNER_MODE_STEREO:
 257                        source = mpx_audio_modes[t->mpxmode].source;
 258                        break;
 259                case V4L2_TUNER_MODE_LANG1:
 260                        source = 0x0300;
 261                        break;
 262                case V4L2_TUNER_MODE_LANG2:
 263                        source = 0x0400;
 264                        break;
 265                }
 266                source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
 267        } else
 268                source = mpx_audio_modes[t->mpxmode].source;
 269
 270        mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
 271        mpx_write(client, 0x12, 0x0008, source);
 272        mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
 273        mpx_write(client, 0x12, 0x000e,
 274                        mpx_audio_modes[t->mpxmode].fm_prescale);
 275        mpx_write(client, 0x12, 0x0010,
 276                        mpx_audio_modes[t->mpxmode].nicam_prescale);
 277        mpx_write(client, 0x12, 0x000d,
 278                        mpx_audio_modes[t->mpxmode].scart_prescale);
 279        mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
 280        mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
 281        if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
 282                mpx_write(client, 0x10, 0x0022,
 283                        t->audmode == V4L2_TUNER_MODE_MONO ?  0x07f0 : 0x0190);
 284
 285#ifdef MPX_DEBUG
 286        {
 287                u8 buf1[3], buf2[2];
 288                struct i2c_msg msgs[2];
 289
 290                printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x "
 291                                "%04x %04x %04x %04x %04x %04x\n",
 292                                mpx_audio_modes[t->mpxmode].modus,
 293                                source,
 294                                mpx_audio_modes[t->mpxmode].acb,
 295                                mpx_audio_modes[t->mpxmode].fm_prescale,
 296                                mpx_audio_modes[t->mpxmode].nicam_prescale,
 297                                mpx_audio_modes[t->mpxmode].scart_prescale,
 298                                mpx_audio_modes[t->mpxmode].system,
 299                                mpx_audio_modes[t->mpxmode].volume);
 300                buf1[0] = 0x11;
 301                buf1[1] = 0x00;
 302                buf1[2] = 0x7e;
 303                msgs[0].addr = MPX_I2C_ADDR;
 304                msgs[0].flags = 0;
 305                msgs[0].len = 3;
 306                msgs[0].buf = buf1;
 307                msgs[1].addr = MPX_I2C_ADDR;
 308                msgs[1].flags = I2C_M_RD;
 309                msgs[1].len = 2;
 310                msgs[1].buf = buf2;
 311                i2c_transfer(client->adapter, msgs, 2);
 312                printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n",
 313                                buf2[0], buf2[1]);
 314                buf1[0] = 0x11;
 315                buf1[1] = 0x02;
 316                buf1[2] = 0x00;
 317                i2c_transfer(client->adapter, msgs, 2);
 318                printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n",
 319                                buf2[0], buf2[1]);
 320        }
 321#endif
 322        return 0;
 323}
 324
 325/*
 326 * IF configuration values for the BTF-PG472Z:
 327 *
 328 *      B/G: 0x94 0x70 0x49
 329 *      I:   0x14 0x70 0x4a
 330 *      D/K: 0x14 0x70 0x4b
 331 *      L:   0x04 0x70 0x4b
 332 *      L':  0x44 0x70 0x53
 333 *      M:   0x50 0x30 0x4c
 334 */
 335
 336static int set_if(struct i2c_client *client)
 337{
 338        struct wis_sony_tuner *t = i2c_get_clientdata(client);
 339        u8 buffer[4];
 340        struct i2c_msg msg;
 341        int default_mpx_mode = 0;
 342
 343        /* configure IF */
 344        buffer[0] = 0;
 345        if (t->std & V4L2_STD_PAL_BG) {
 346                buffer[1] = 0x94;
 347                buffer[2] = 0x70;
 348                buffer[3] = 0x49;
 349                default_mpx_mode = 1;
 350        } else if (t->std & V4L2_STD_PAL_I) {
 351                buffer[1] = 0x14;
 352                buffer[2] = 0x70;
 353                buffer[3] = 0x4a;
 354                default_mpx_mode = 4;
 355        } else if (t->std & V4L2_STD_PAL_DK) {
 356                buffer[1] = 0x14;
 357                buffer[2] = 0x70;
 358                buffer[3] = 0x4b;
 359                default_mpx_mode = 6;
 360        } else if (t->std & V4L2_STD_SECAM_L) {
 361                buffer[1] = 0x04;
 362                buffer[2] = 0x70;
 363                buffer[3] = 0x4b;
 364                default_mpx_mode = 11;
 365        }
 366        msg.addr = IF_I2C_ADDR;
 367        msg.flags = 0;
 368        msg.len = 4;
 369        msg.buf = buffer;
 370        i2c_transfer(client->adapter, &msg, 1);
 371
 372        /* Select MPX mode if not forced by the user */
 373        if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES)
 374                t->mpxmode = force_mpx_mode;
 375        else
 376                t->mpxmode = default_mpx_mode;
 377        printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n",
 378                        t->mpxmode);
 379        mpx_setup(client);
 380
 381        return 0;
 382}
 383
 384static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 385{
 386        struct wis_sony_tuner *t = i2c_get_clientdata(client);
 387
 388        switch (cmd) {
 389#if 0
 390#ifdef TUNER_SET_TYPE_ADDR
 391        case TUNER_SET_TYPE_ADDR:
 392        {
 393                struct tuner_setup *tun_setup = arg;
 394                int *type = &tun_setup->type;
 395#else
 396        case TUNER_SET_TYPE:
 397        {
 398                int *type = arg;
 399#endif
 400
 401                if (t->type >= 0) {
 402                        if (t->type != *type)
 403                                printk(KERN_ERR "wis-sony-tuner: type already "
 404                                        "set to %d, ignoring request for %d\n",
 405                                        t->type, *type);
 406                        break;
 407                }
 408                t->type = *type;
 409                switch (t->type) {
 410                case TUNER_SONY_BTF_PG472Z:
 411                        switch (force_band_str[0]) {
 412                        case 'b':
 413                        case 'B':
 414                        case 'g':
 415                        case 'G':
 416                                printk(KERN_INFO "wis-sony-tuner: forcing "
 417                                                "tuner to PAL-B/G bands\n");
 418                                force_band = V4L2_STD_PAL_BG;
 419                                break;
 420                        case 'i':
 421                        case 'I':
 422                                printk(KERN_INFO "wis-sony-tuner: forcing "
 423                                                "tuner to PAL-I band\n");
 424                                force_band = V4L2_STD_PAL_I;
 425                                break;
 426                        case 'd':
 427                        case 'D':
 428                        case 'k':
 429                        case 'K':
 430                                printk(KERN_INFO "wis-sony-tuner: forcing "
 431                                                "tuner to PAL-D/K bands\n");
 432                                force_band = V4L2_STD_PAL_I;
 433                                break;
 434                        case 'l':
 435                        case 'L':
 436                                printk(KERN_INFO "wis-sony-tuner: forcing "
 437                                                "tuner to SECAM-L band\n");
 438                                force_band = V4L2_STD_SECAM_L;
 439                                break;
 440                        default:
 441                                force_band = 0;
 442                                break;
 443                        }
 444                        if (force_band)
 445                                t->std = force_band;
 446                        else
 447                                t->std = V4L2_STD_PAL_BG;
 448                        set_if(client);
 449                        break;
 450                case TUNER_SONY_BTF_PK467Z:
 451                        t->std = V4L2_STD_NTSC_M_JP;
 452                        break;
 453                case TUNER_SONY_BTF_PB463Z:
 454                        t->std = V4L2_STD_NTSC_M;
 455                        break;
 456                default:
 457                        printk(KERN_ERR "wis-sony-tuner: tuner type %d is not "
 458                                        "supported by this module\n", *type);
 459                        break;
 460                }
 461                if (type >= 0)
 462                        printk(KERN_INFO
 463                                "wis-sony-tuner: type set to %d (%s)\n",
 464                                t->type, sony_tuners[t->type - 200].name);
 465                break;
 466        }
 467#endif
 468        case VIDIOC_G_FREQUENCY:
 469        {
 470                struct v4l2_frequency *f = arg;
 471
 472                f->frequency = t->freq;
 473                break;
 474        }
 475        case VIDIOC_S_FREQUENCY:
 476        {
 477                struct v4l2_frequency *f = arg;
 478
 479                t->freq = f->frequency;
 480                set_freq(client, t->freq);
 481                break;
 482        }
 483        case VIDIOC_ENUMSTD:
 484        {
 485                struct v4l2_standard *std = arg;
 486
 487                switch (t->type) {
 488                case TUNER_SONY_BTF_PG472Z:
 489                        switch (std->index) {
 490                        case 0:
 491                                v4l2_video_std_construct(std,
 492                                                V4L2_STD_PAL_BG, "PAL-B/G");
 493                                break;
 494                        case 1:
 495                                v4l2_video_std_construct(std,
 496                                                V4L2_STD_PAL_I, "PAL-I");
 497                                break;
 498                        case 2:
 499                                v4l2_video_std_construct(std,
 500                                                V4L2_STD_PAL_DK, "PAL-D/K");
 501                                break;
 502                        case 3:
 503                                v4l2_video_std_construct(std,
 504                                                V4L2_STD_SECAM_L, "SECAM-L");
 505                                break;
 506                        default:
 507                                std->id = 0; /* hack to indicate EINVAL */
 508                                break;
 509                        }
 510                        break;
 511                case TUNER_SONY_BTF_PK467Z:
 512                        if (std->index != 0) {
 513                                std->id = 0; /* hack to indicate EINVAL */
 514                                break;
 515                        }
 516                        v4l2_video_std_construct(std,
 517                                        V4L2_STD_NTSC_M_JP, "NTSC-J");
 518                        break;
 519                case TUNER_SONY_BTF_PB463Z:
 520                        if (std->index != 0) {
 521                                std->id = 0; /* hack to indicate EINVAL */
 522                                break;
 523                        }
 524                        v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
 525                        break;
 526                }
 527                break;
 528        }
 529        case VIDIOC_G_STD:
 530        {
 531                v4l2_std_id *std = arg;
 532
 533                *std = t->std;
 534                break;
 535        }
 536        case VIDIOC_S_STD:
 537        {
 538                v4l2_std_id *std = arg;
 539                v4l2_std_id old = t->std;
 540
 541                switch (t->type) {
 542                case TUNER_SONY_BTF_PG472Z:
 543                        if (force_band && (*std & force_band) != *std &&
 544                                        *std != V4L2_STD_PAL &&
 545                                        *std != V4L2_STD_SECAM) {
 546                                printk(KERN_DEBUG "wis-sony-tuner: ignoring "
 547                                                "requested TV standard in "
 548                                                "favor of force_band value\n");
 549                                t->std = force_band;
 550                        } else if (*std & V4L2_STD_PAL_BG) { /* default */
 551                                t->std = V4L2_STD_PAL_BG;
 552                        } else if (*std & V4L2_STD_PAL_I) {
 553                                t->std = V4L2_STD_PAL_I;
 554                        } else if (*std & V4L2_STD_PAL_DK) {
 555                                t->std = V4L2_STD_PAL_DK;
 556                        } else if (*std & V4L2_STD_SECAM_L) {
 557                                t->std = V4L2_STD_SECAM_L;
 558                        } else {
 559                                printk(KERN_ERR "wis-sony-tuner: TV standard "
 560                                                "not supported\n");
 561                                *std = 0; /* hack to indicate EINVAL */
 562                                break;
 563                        }
 564                        if (old != t->std)
 565                                set_if(client);
 566                        break;
 567                case TUNER_SONY_BTF_PK467Z:
 568                        if (!(*std & V4L2_STD_NTSC_M_JP)) {
 569                                printk(KERN_ERR "wis-sony-tuner: TV standard "
 570                                                "not supported\n");
 571                                *std = 0; /* hack to indicate EINVAL */
 572                        }
 573                        break;
 574                case TUNER_SONY_BTF_PB463Z:
 575                        if (!(*std & V4L2_STD_NTSC_M)) {
 576                                printk(KERN_ERR "wis-sony-tuner: TV standard "
 577                                                "not supported\n");
 578                                *std = 0; /* hack to indicate EINVAL */
 579                        }
 580                        break;
 581                }
 582                break;
 583        }
 584        case VIDIOC_QUERYSTD:
 585        {
 586                v4l2_std_id *std = arg;
 587
 588                switch (t->type) {
 589                case TUNER_SONY_BTF_PG472Z:
 590                        if (force_band)
 591                                *std = force_band;
 592                        else
 593                                *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
 594                                        V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
 595                        break;
 596                case TUNER_SONY_BTF_PK467Z:
 597                        *std = V4L2_STD_NTSC_M_JP;
 598                        break;
 599                case TUNER_SONY_BTF_PB463Z:
 600                        *std = V4L2_STD_NTSC_M;
 601                        break;
 602                }
 603                break;
 604        }
 605        case VIDIOC_G_TUNER:
 606        {
 607                struct v4l2_tuner *tun = arg;
 608
 609                memset(tun, 0, sizeof(*tun));
 610                strcpy(tun->name, "Television");
 611                tun->type = V4L2_TUNER_ANALOG_TV;
 612                tun->rangelow = 0UL; /* does anything use these? */
 613                tun->rangehigh = 0xffffffffUL;
 614                switch (t->type) {
 615                case TUNER_SONY_BTF_PG472Z:
 616                        tun->capability = V4L2_TUNER_CAP_NORM |
 617                                V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
 618                                V4L2_TUNER_CAP_LANG2;
 619                        tun->rxsubchans = V4L2_TUNER_SUB_MONO |
 620                                V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
 621                                V4L2_TUNER_SUB_LANG2;
 622                        break;
 623                case TUNER_SONY_BTF_PK467Z:
 624                case TUNER_SONY_BTF_PB463Z:
 625                        tun->capability = V4L2_TUNER_CAP_STEREO;
 626                        tun->rxsubchans = V4L2_TUNER_SUB_MONO |
 627                                                V4L2_TUNER_SUB_STEREO;
 628                        break;
 629                }
 630                tun->audmode = t->audmode;
 631                return 0;
 632        }
 633        case VIDIOC_S_TUNER:
 634        {
 635                struct v4l2_tuner *tun = arg;
 636
 637                switch (t->type) {
 638                case TUNER_SONY_BTF_PG472Z:
 639                        if (tun->audmode != t->audmode) {
 640                                t->audmode = tun->audmode;
 641                                mpx_setup(client);
 642                        }
 643                        break;
 644                case TUNER_SONY_BTF_PK467Z:
 645                case TUNER_SONY_BTF_PB463Z:
 646                        break;
 647                }
 648                return 0;
 649        }
 650        default:
 651                break;
 652        }
 653        return 0;
 654}
 655
 656static int wis_sony_tuner_probe(struct i2c_client *client,
 657                                const struct i2c_device_id *id)
 658{
 659        struct i2c_adapter *adapter = client->adapter;
 660        struct wis_sony_tuner *t;
 661
 662        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
 663                return -ENODEV;
 664
 665        t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
 666        if (t == NULL)
 667                return -ENOMEM;
 668
 669        t->type = -1;
 670        t->freq = 0;
 671        t->mpxmode = 0;
 672        t->audmode = V4L2_TUNER_MODE_STEREO;
 673        i2c_set_clientdata(client, t);
 674
 675        printk(KERN_DEBUG
 676                "wis-sony-tuner: initializing tuner at address %d on %s\n",
 677                client->addr, adapter->name);
 678
 679        return 0;
 680}
 681
 682static int wis_sony_tuner_remove(struct i2c_client *client)
 683{
 684        struct wis_sony_tuner *t = i2c_get_clientdata(client);
 685
 686        i2c_set_clientdata(client, NULL);
 687        kfree(t);
 688        return 0;
 689}
 690
 691static struct i2c_device_id wis_sony_tuner_id[] = {
 692        { "wis_sony_tuner", 0 },
 693        { }
 694};
 695
 696static struct i2c_driver wis_sony_tuner_driver = {
 697        .driver = {
 698                .name   = "WIS Sony TV Tuner I2C driver",
 699        },
 700        .probe          = wis_sony_tuner_probe,
 701        .remove         = wis_sony_tuner_remove,
 702        .command        = tuner_command,
 703        .id_table       = wis_sony_tuner_id,
 704};
 705
 706static int __init wis_sony_tuner_init(void)
 707{
 708        return i2c_add_driver(&wis_sony_tuner_driver);
 709}
 710
 711static void __exit wis_sony_tuner_cleanup(void)
 712{
 713        i2c_del_driver(&wis_sony_tuner_driver);
 714}
 715
 716module_init(wis_sony_tuner_init);
 717module_exit(wis_sony_tuner_cleanup);
 718
 719MODULE_LICENSE("GPL v2");
 720