linux/drivers/media/radio/radio-tea5764.c
<<
>>
Prefs
   1/*
   2 * driver/media/radio/radio-tea5764.c
   3 *
   4 * Driver for TEA5764 radio chip for linux 2.6.
   5 * This driver is for TEA5764 chip from NXP, used in EZX phones from Motorola.
   6 * The I2C protocol is used for communicate with chip.
   7 *
   8 * Based in radio-tea5761.c Copyright (C) 2005 Nokia Corporation
   9 *
  10 *  Copyright (c) 2008 Fabio Belavenuto <belavenuto@gmail.com>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25 *
  26 * History:
  27 * 2008-12-06   Fabio Belavenuto <belavenuto@gmail.com>
  28 *              initial code
  29 *
  30 * TODO:
  31 *  add platform_data support for IRQs platform dependencies
  32 *  add RDS support
  33 */
  34#include <linux/kernel.h>
  35#include <linux/module.h>
  36#include <linux/init.h>                 /* Initdata                     */
  37#include <linux/videodev2.h>            /* kernel radio structs         */
  38#include <linux/i2c.h>                  /* I2C                          */
  39#include <media/v4l2-common.h>
  40#include <media/v4l2-ioctl.h>
  41#include <linux/version.h>              /* for KERNEL_VERSION MACRO     */
  42
  43#define DRIVER_VERSION  "v0.01"
  44#define RADIO_VERSION   KERNEL_VERSION(0, 0, 1)
  45
  46#define DRIVER_AUTHOR   "Fabio Belavenuto <belavenuto@gmail.com>"
  47#define DRIVER_DESC     "A driver for the TEA5764 radio chip for EZX Phones."
  48
  49#define PINFO(format, ...)\
  50        printk(KERN_INFO KBUILD_MODNAME ": "\
  51                DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
  52#define PWARN(format, ...)\
  53        printk(KERN_WARNING KBUILD_MODNAME ": "\
  54                DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
  55# define PDEBUG(format, ...)\
  56        printk(KERN_DEBUG KBUILD_MODNAME ": "\
  57                DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
  58
  59/* Frequency limits in MHz -- these are European values.  For Japanese
  60devices, that would be 76000 and 91000.  */
  61#define FREQ_MIN  87500
  62#define FREQ_MAX 108000
  63#define FREQ_MUL 16
  64
  65/* TEA5764 registers */
  66#define TEA5764_MANID           0x002b
  67#define TEA5764_CHIPID          0x5764
  68
  69#define TEA5764_INTREG_BLMSK    0x0001
  70#define TEA5764_INTREG_FRRMSK   0x0002
  71#define TEA5764_INTREG_LEVMSK   0x0008
  72#define TEA5764_INTREG_IFMSK    0x0010
  73#define TEA5764_INTREG_BLMFLAG  0x0100
  74#define TEA5764_INTREG_FRRFLAG  0x0200
  75#define TEA5764_INTREG_LEVFLAG  0x0800
  76#define TEA5764_INTREG_IFFLAG   0x1000
  77
  78#define TEA5764_FRQSET_SUD      0x8000
  79#define TEA5764_FRQSET_SM       0x4000
  80
  81#define TEA5764_TNCTRL_PUPD1    0x8000
  82#define TEA5764_TNCTRL_PUPD0    0x4000
  83#define TEA5764_TNCTRL_BLIM     0x2000
  84#define TEA5764_TNCTRL_SWPM     0x1000
  85#define TEA5764_TNCTRL_IFCTC    0x0800
  86#define TEA5764_TNCTRL_AFM      0x0400
  87#define TEA5764_TNCTRL_SMUTE    0x0200
  88#define TEA5764_TNCTRL_SNC      0x0100
  89#define TEA5764_TNCTRL_MU       0x0080
  90#define TEA5764_TNCTRL_SSL1     0x0040
  91#define TEA5764_TNCTRL_SSL0     0x0020
  92#define TEA5764_TNCTRL_HLSI     0x0010
  93#define TEA5764_TNCTRL_MST      0x0008
  94#define TEA5764_TNCTRL_SWP      0x0004
  95#define TEA5764_TNCTRL_DTC      0x0002
  96#define TEA5764_TNCTRL_AHLSI    0x0001
  97
  98#define TEA5764_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4)
  99#define TEA5764_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
 100#define TEA5764_TUNCHK_TUNTO    0x0100
 101#define TEA5764_TUNCHK_LD       0x0008
 102#define TEA5764_TUNCHK_STEREO   0x0004
 103
 104#define TEA5764_TESTREG_TRIGFR  0x0800
 105
 106struct tea5764_regs {
 107        u16 intreg;                             /* INTFLAG & INTMSK */
 108        u16 frqset;                             /* FRQSETMSB & FRQSETLSB */
 109        u16 tnctrl;                             /* TNCTRL1 & TNCTRL2 */
 110        u16 frqchk;                             /* FRQCHKMSB & FRQCHKLSB */
 111        u16 tunchk;                             /* IFCHK & LEVCHK */
 112        u16 testreg;                            /* TESTBITS & TESTMODE */
 113        u16 rdsstat;                            /* RDSSTAT1 & RDSSTAT2 */
 114        u16 rdslb;                              /* RDSLBMSB & RDSLBLSB */
 115        u16 rdspb;                              /* RDSPBMSB & RDSPBLSB */
 116        u16 rdsbc;                              /* RDSBBC & RDSGBC */
 117        u16 rdsctrl;                            /* RDSCTRL1 & RDSCTRL2 */
 118        u16 rdsbbl;                             /* PAUSEDET & RDSBBL */
 119        u16 manid;                              /* MANID1 & MANID2 */
 120        u16 chipid;                             /* CHIPID1 & CHIPID2 */
 121} __attribute__ ((packed));
 122
 123struct tea5764_write_regs {
 124        u8 intreg;                              /* INTMSK */
 125        u16 frqset;                             /* FRQSETMSB & FRQSETLSB */
 126        u16 tnctrl;                             /* TNCTRL1 & TNCTRL2 */
 127        u16 testreg;                            /* TESTBITS & TESTMODE */
 128        u16 rdsctrl;                            /* RDSCTRL1 & RDSCTRL2 */
 129        u16 rdsbbl;                             /* PAUSEDET & RDSBBL */
 130} __attribute__ ((packed));
 131
 132#ifndef RADIO_TEA5764_XTAL
 133#define RADIO_TEA5764_XTAL 1
 134#endif
 135
 136static int radio_nr = -1;
 137static int use_xtal = RADIO_TEA5764_XTAL;
 138
 139struct tea5764_device {
 140        struct i2c_client               *i2c_client;
 141        struct video_device             *videodev;
 142        struct tea5764_regs             regs;
 143        struct mutex                    mutex;
 144        int                             users;
 145};
 146
 147/* I2C code related */
 148int tea5764_i2c_read(struct tea5764_device *radio)
 149{
 150        int i;
 151        u16 *p = (u16 *) &radio->regs;
 152
 153        struct i2c_msg msgs[1] = {
 154                { radio->i2c_client->addr, I2C_M_RD, sizeof(radio->regs),
 155                        (void *)&radio->regs },
 156        };
 157        if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
 158                return -EIO;
 159        for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++)
 160                p[i] = __be16_to_cpu(p[i]);
 161
 162        return 0;
 163}
 164
 165int tea5764_i2c_write(struct tea5764_device *radio)
 166{
 167        struct tea5764_write_regs wr;
 168        struct tea5764_regs *r = &radio->regs;
 169        struct i2c_msg msgs[1] = {
 170                { radio->i2c_client->addr, 0, sizeof(wr), (void *) &wr },
 171        };
 172        wr.intreg  = r->intreg & 0xff;
 173        wr.frqset  = __cpu_to_be16(r->frqset);
 174        wr.tnctrl  = __cpu_to_be16(r->tnctrl);
 175        wr.testreg = __cpu_to_be16(r->testreg);
 176        wr.rdsctrl = __cpu_to_be16(r->rdsctrl);
 177        wr.rdsbbl  = __cpu_to_be16(r->rdsbbl);
 178        if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
 179                return -EIO;
 180        return 0;
 181}
 182
 183/* V4L2 code related */
 184static struct v4l2_queryctrl radio_qctrl[] = {
 185        {
 186                .id            = V4L2_CID_AUDIO_MUTE,
 187                .name          = "Mute",
 188                .minimum       = 0,
 189                .maximum       = 1,
 190                .default_value = 1,
 191                .type          = V4L2_CTRL_TYPE_BOOLEAN,
 192        }
 193};
 194
 195static void tea5764_power_up(struct tea5764_device *radio)
 196{
 197        struct tea5764_regs *r = &radio->regs;
 198
 199        if (!(r->tnctrl & TEA5764_TNCTRL_PUPD0)) {
 200                r->tnctrl &= ~(TEA5764_TNCTRL_AFM | TEA5764_TNCTRL_MU |
 201                               TEA5764_TNCTRL_HLSI);
 202                if (!use_xtal)
 203                        r->testreg |= TEA5764_TESTREG_TRIGFR;
 204                else
 205                        r->testreg &= ~TEA5764_TESTREG_TRIGFR;
 206
 207                r->tnctrl |= TEA5764_TNCTRL_PUPD0;
 208                tea5764_i2c_write(radio);
 209        }
 210}
 211
 212static void tea5764_power_down(struct tea5764_device *radio)
 213{
 214        struct tea5764_regs *r = &radio->regs;
 215
 216        if (r->tnctrl & TEA5764_TNCTRL_PUPD0) {
 217                r->tnctrl &= ~TEA5764_TNCTRL_PUPD0;
 218                tea5764_i2c_write(radio);
 219        }
 220}
 221
 222static void tea5764_set_freq(struct tea5764_device *radio, int freq)
 223{
 224        struct tea5764_regs *r = &radio->regs;
 225
 226        /* formula: (freq [+ or -] 225000) / 8192 */
 227        if (r->tnctrl & TEA5764_TNCTRL_HLSI)
 228                r->frqset = (freq + 225000) / 8192;
 229        else
 230                r->frqset = (freq - 225000) / 8192;
 231}
 232
 233static int tea5764_get_freq(struct tea5764_device *radio)
 234{
 235        struct tea5764_regs *r = &radio->regs;
 236
 237        if (r->tnctrl & TEA5764_TNCTRL_HLSI)
 238                return (r->frqchk * 8192) - 225000;
 239        else
 240                return (r->frqchk * 8192) + 225000;
 241}
 242
 243/* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
 244static void tea5764_tune(struct tea5764_device *radio, int freq)
 245{
 246        tea5764_set_freq(radio, freq);
 247        if (tea5764_i2c_write(radio))
 248                PWARN("Could not set frequency!");
 249}
 250
 251static void tea5764_set_audout_mode(struct tea5764_device *radio, int audmode)
 252{
 253        struct tea5764_regs *r = &radio->regs;
 254        int tnctrl = r->tnctrl;
 255
 256        if (audmode == V4L2_TUNER_MODE_MONO)
 257                r->tnctrl |= TEA5764_TNCTRL_MST;
 258        else
 259                r->tnctrl &= ~TEA5764_TNCTRL_MST;
 260        if (tnctrl != r->tnctrl)
 261                tea5764_i2c_write(radio);
 262}
 263
 264static int tea5764_get_audout_mode(struct tea5764_device *radio)
 265{
 266        struct tea5764_regs *r = &radio->regs;
 267
 268        if (r->tnctrl & TEA5764_TNCTRL_MST)
 269                return V4L2_TUNER_MODE_MONO;
 270        else
 271                return V4L2_TUNER_MODE_STEREO;
 272}
 273
 274static void tea5764_mute(struct tea5764_device *radio, int on)
 275{
 276        struct tea5764_regs *r = &radio->regs;
 277        int tnctrl = r->tnctrl;
 278
 279        if (on)
 280                r->tnctrl |= TEA5764_TNCTRL_MU;
 281        else
 282                r->tnctrl &= ~TEA5764_TNCTRL_MU;
 283        if (tnctrl != r->tnctrl)
 284                tea5764_i2c_write(radio);
 285}
 286
 287static int tea5764_is_muted(struct tea5764_device *radio)
 288{
 289        return radio->regs.tnctrl & TEA5764_TNCTRL_MU;
 290}
 291
 292/* V4L2 vidioc */
 293static int vidioc_querycap(struct file *file, void  *priv,
 294                                        struct v4l2_capability *v)
 295{
 296        struct tea5764_device *radio = video_drvdata(file);
 297        struct video_device *dev = radio->videodev;
 298
 299        strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
 300        strlcpy(v->card, dev->name, sizeof(v->card));
 301        snprintf(v->bus_info, sizeof(v->bus_info),
 302                 "I2C:%s", dev_name(&dev->dev));
 303        v->version = RADIO_VERSION;
 304        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 305        return 0;
 306}
 307
 308static int vidioc_g_tuner(struct file *file, void *priv,
 309                                struct v4l2_tuner *v)
 310{
 311        struct tea5764_device *radio = video_drvdata(file);
 312        struct tea5764_regs *r = &radio->regs;
 313
 314        if (v->index > 0)
 315                return -EINVAL;
 316
 317        memset(v, 0, sizeof(v));
 318        strcpy(v->name, "FM");
 319        v->type = V4L2_TUNER_RADIO;
 320        tea5764_i2c_read(radio);
 321        v->rangelow   = FREQ_MIN * FREQ_MUL;
 322        v->rangehigh  = FREQ_MAX * FREQ_MUL;
 323        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 324        if (r->tunchk & TEA5764_TUNCHK_STEREO)
 325                v->rxsubchans = V4L2_TUNER_SUB_STEREO;
 326        else
 327                v->rxsubchans = V4L2_TUNER_SUB_MONO;
 328        v->audmode = tea5764_get_audout_mode(radio);
 329        v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
 330        v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk);
 331
 332        return 0;
 333}
 334
 335static int vidioc_s_tuner(struct file *file, void *priv,
 336                                struct v4l2_tuner *v)
 337{
 338        struct tea5764_device *radio = video_drvdata(file);
 339
 340        if (v->index > 0)
 341                return -EINVAL;
 342
 343        tea5764_set_audout_mode(radio, v->audmode);
 344        return 0;
 345}
 346
 347static int vidioc_s_frequency(struct file *file, void *priv,
 348                                struct v4l2_frequency *f)
 349{
 350        struct tea5764_device *radio = video_drvdata(file);
 351
 352        if (f->tuner != 0)
 353                return -EINVAL;
 354        if (f->frequency == 0) {
 355                /* We special case this as a power down control. */
 356                tea5764_power_down(radio);
 357        }
 358        if (f->frequency < (FREQ_MIN * FREQ_MUL))
 359                return -EINVAL;
 360        if (f->frequency > (FREQ_MAX * FREQ_MUL))
 361                return -EINVAL;
 362        tea5764_power_up(radio);
 363        tea5764_tune(radio, (f->frequency * 125) / 2);
 364        return 0;
 365}
 366
 367static int vidioc_g_frequency(struct file *file, void *priv,
 368                                struct v4l2_frequency *f)
 369{
 370        struct tea5764_device *radio = video_drvdata(file);
 371        struct tea5764_regs *r = &radio->regs;
 372
 373        tea5764_i2c_read(radio);
 374        memset(f, 0, sizeof(f));
 375        f->type = V4L2_TUNER_RADIO;
 376        if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
 377                f->frequency = (tea5764_get_freq(radio) * 2) / 125;
 378        else
 379                f->frequency = 0;
 380
 381        return 0;
 382}
 383
 384static int vidioc_queryctrl(struct file *file, void *priv,
 385                            struct v4l2_queryctrl *qc)
 386{
 387        int i;
 388
 389        for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
 390                if (qc->id && qc->id == radio_qctrl[i].id) {
 391                        memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
 392                        return 0;
 393                }
 394        }
 395        return -EINVAL;
 396}
 397
 398static int vidioc_g_ctrl(struct file *file, void *priv,
 399                            struct v4l2_control *ctrl)
 400{
 401        struct tea5764_device *radio = video_drvdata(file);
 402
 403        switch (ctrl->id) {
 404        case V4L2_CID_AUDIO_MUTE:
 405                tea5764_i2c_read(radio);
 406                ctrl->value = tea5764_is_muted(radio) ? 1 : 0;
 407                return 0;
 408        }
 409        return -EINVAL;
 410}
 411
 412static int vidioc_s_ctrl(struct file *file, void *priv,
 413                            struct v4l2_control *ctrl)
 414{
 415        struct tea5764_device *radio = video_drvdata(file);
 416
 417        switch (ctrl->id) {
 418        case V4L2_CID_AUDIO_MUTE:
 419                tea5764_mute(radio, ctrl->value);
 420                return 0;
 421        }
 422        return -EINVAL;
 423}
 424
 425static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 426{
 427        *i = 0;
 428        return 0;
 429}
 430
 431static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 432{
 433        if (i != 0)
 434                return -EINVAL;
 435        return 0;
 436}
 437
 438static int vidioc_g_audio(struct file *file, void *priv,
 439                           struct v4l2_audio *a)
 440{
 441        if (a->index > 1)
 442                return -EINVAL;
 443
 444        strcpy(a->name, "Radio");
 445        a->capability = V4L2_AUDCAP_STEREO;
 446        return 0;
 447}
 448
 449static int vidioc_s_audio(struct file *file, void *priv,
 450                           struct v4l2_audio *a)
 451{
 452        if (a->index != 0)
 453                return -EINVAL;
 454
 455        return 0;
 456}
 457
 458static int tea5764_open(struct file *file)
 459{
 460        /* Currently we support only one device */
 461        int minor = video_devdata(file)->minor;
 462        struct tea5764_device *radio = video_drvdata(file);
 463
 464        if (radio->videodev->minor != minor)
 465                return -ENODEV;
 466
 467        mutex_lock(&radio->mutex);
 468        /* Only exclusive access */
 469        if (radio->users) {
 470                mutex_unlock(&radio->mutex);
 471                return -EBUSY;
 472        }
 473        radio->users++;
 474        mutex_unlock(&radio->mutex);
 475        file->private_data = radio;
 476        return 0;
 477}
 478
 479static int tea5764_close(struct file *file)
 480{
 481        struct tea5764_device *radio = video_drvdata(file);
 482
 483        if (!radio)
 484                return -ENODEV;
 485        mutex_lock(&radio->mutex);
 486        radio->users--;
 487        mutex_unlock(&radio->mutex);
 488        return 0;
 489}
 490
 491/* File system interface */
 492static const struct v4l2_file_operations tea5764_fops = {
 493        .owner          = THIS_MODULE,
 494        .open           = tea5764_open,
 495        .release        = tea5764_close,
 496        .ioctl          = video_ioctl2,
 497};
 498
 499static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
 500        .vidioc_querycap    = vidioc_querycap,
 501        .vidioc_g_tuner     = vidioc_g_tuner,
 502        .vidioc_s_tuner     = vidioc_s_tuner,
 503        .vidioc_g_audio     = vidioc_g_audio,
 504        .vidioc_s_audio     = vidioc_s_audio,
 505        .vidioc_g_input     = vidioc_g_input,
 506        .vidioc_s_input     = vidioc_s_input,
 507        .vidioc_g_frequency = vidioc_g_frequency,
 508        .vidioc_s_frequency = vidioc_s_frequency,
 509        .vidioc_queryctrl   = vidioc_queryctrl,
 510        .vidioc_g_ctrl      = vidioc_g_ctrl,
 511        .vidioc_s_ctrl      = vidioc_s_ctrl,
 512};
 513
 514/* V4L2 interface */
 515static struct video_device tea5764_radio_template = {
 516        .name           = "TEA5764 FM-Radio",
 517        .fops           = &tea5764_fops,
 518        .ioctl_ops      = &tea5764_ioctl_ops,
 519        .release        = video_device_release,
 520};
 521
 522/* I2C probe: check if the device exists and register with v4l if it is */
 523static int __devinit tea5764_i2c_probe(struct i2c_client *client,
 524                                        const struct i2c_device_id *id)
 525{
 526        struct tea5764_device *radio;
 527        struct tea5764_regs *r;
 528        int ret;
 529
 530        PDEBUG("probe");
 531        radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL);
 532        if (!radio)
 533                return -ENOMEM;
 534
 535        mutex_init(&radio->mutex);
 536        radio->i2c_client = client;
 537        ret = tea5764_i2c_read(radio);
 538        if (ret)
 539                goto errfr;
 540        r = &radio->regs;
 541        PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid);
 542        if (r->chipid != TEA5764_CHIPID ||
 543                (r->manid & 0x0fff) != TEA5764_MANID) {
 544                PWARN("This chip is not a TEA5764!");
 545                ret = -EINVAL;
 546                goto errfr;
 547        }
 548
 549        radio->videodev = video_device_alloc();
 550        if (!(radio->videodev)) {
 551                ret = -ENOMEM;
 552                goto errfr;
 553        }
 554        memcpy(radio->videodev, &tea5764_radio_template,
 555                sizeof(tea5764_radio_template));
 556
 557        i2c_set_clientdata(client, radio);
 558        video_set_drvdata(radio->videodev, radio);
 559
 560        ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
 561        if (ret < 0) {
 562                PWARN("Could not register video device!");
 563                goto errrel;
 564        }
 565
 566        /* initialize and power off the chip */
 567        tea5764_i2c_read(radio);
 568        tea5764_set_audout_mode(radio, V4L2_TUNER_MODE_STEREO);
 569        tea5764_mute(radio, 1);
 570        tea5764_power_down(radio);
 571
 572        PINFO("registered.");
 573        return 0;
 574errrel:
 575        video_device_release(radio->videodev);
 576errfr:
 577        kfree(radio);
 578        return ret;
 579}
 580
 581static int __devexit tea5764_i2c_remove(struct i2c_client *client)
 582{
 583        struct tea5764_device *radio = i2c_get_clientdata(client);
 584
 585        PDEBUG("remove");
 586        if (radio) {
 587                tea5764_power_down(radio);
 588                video_unregister_device(radio->videodev);
 589                kfree(radio);
 590        }
 591        return 0;
 592}
 593
 594/* I2C subsystem interface */
 595static const struct i2c_device_id tea5764_id[] = {
 596        { "radio-tea5764", 0 },
 597        { }                                     /* Terminating entry */
 598};
 599MODULE_DEVICE_TABLE(i2c, tea5764_id);
 600
 601static struct i2c_driver tea5764_i2c_driver = {
 602        .driver = {
 603                .name = "radio-tea5764",
 604                .owner = THIS_MODULE,
 605        },
 606        .probe = tea5764_i2c_probe,
 607        .remove = __devexit_p(tea5764_i2c_remove),
 608        .id_table = tea5764_id,
 609};
 610
 611/* init the driver */
 612static int __init tea5764_init(void)
 613{
 614        int ret = i2c_add_driver(&tea5764_i2c_driver);
 615
 616        printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
 617                DRIVER_DESC "\n");
 618        return ret;
 619}
 620
 621/* cleanup the driver */
 622static void __exit tea5764_exit(void)
 623{
 624        i2c_del_driver(&tea5764_i2c_driver);
 625}
 626
 627MODULE_AUTHOR(DRIVER_AUTHOR);
 628MODULE_DESCRIPTION(DRIVER_DESC);
 629MODULE_LICENSE("GPL");
 630
 631module_param(use_xtal, int, 1);
 632MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
 633module_param(radio_nr, int, 0);
 634MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
 635
 636module_init(tea5764_init);
 637module_exit(tea5764_exit);
 638