linux/drivers/media/radio/radio-maxiradio.c
<<
>>
Prefs
   1/*
   2 * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
   3 * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
   4 *
   5 * Based in the radio Maestro PCI driver. Actually it uses the same chip
   6 * for radio but different pci controller.
   7 *
   8 * I didn't have any specs I reversed engineered the protocol from
   9 * the windows driver (radio.dll).
  10 *
  11 * The card uses the TEA5757 chip that includes a search function but it
  12 * is useless as I haven't found any way to read back the frequency. If
  13 * anybody does please mail me.
  14 *
  15 * For the pdf file see:
  16 * http://www.semiconductors.philips.com/pip/TEA5757H/V1
  17 *
  18 *
  19 * CHANGES:
  20 *   0.75b
  21 *     - better pci interface thanks to Francois Romieu <romieu@cogenit.fr>
  22 *
  23 *   0.75      Sun Feb  4 22:51:27 EET 2001
  24 *     - tiding up
  25 *     - removed support for multiple devices as it didn't work anyway
  26 *
  27 * BUGS:
  28 *   - card unmutes if you change frequency
  29 *
  30 * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>:
  31 *      - Conversion to V4L2 API
  32 *      - Uses video_ioctl2 for parsing and to add debug support
  33 */
  34
  35
  36#include <linux/module.h>
  37#include <linux/init.h>
  38#include <linux/ioport.h>
  39#include <linux/delay.h>
  40#include <linux/mutex.h>
  41#include <linux/pci.h>
  42#include <linux/videodev2.h>
  43#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
  44#include <linux/io.h>
  45#include <media/v4l2-device.h>
  46#include <media/v4l2-ioctl.h>
  47
  48MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
  49MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
  50MODULE_LICENSE("GPL");
  51
  52static int radio_nr = -1;
  53module_param(radio_nr, int, 0);
  54
  55static int debug;
  56
  57module_param(debug, int, 0644);
  58MODULE_PARM_DESC(debug, "activates debug info");
  59
  60#define DRIVER_VERSION  "0.77"
  61
  62#define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
  63
  64#define dprintk(dev, num, fmt, arg...) \
  65        v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
  66
  67#ifndef PCI_VENDOR_ID_GUILLEMOT
  68#define PCI_VENDOR_ID_GUILLEMOT 0x5046
  69#endif
  70
  71#ifndef PCI_DEVICE_ID_GUILLEMOT
  72#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
  73#endif
  74
  75
  76/* TEA5757 pin mappings */
  77static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
  78
  79#define FREQ_LO         (50 * 16000)
  80#define FREQ_HI         (150 * 16000)
  81
  82#define FREQ_IF         171200 /* 10.7*16000   */
  83#define FREQ_STEP       200    /* 12.5*16      */
  84
  85/* (x==fmhz*16*1000) -> bits */
  86#define FREQ2BITS(x) \
  87  ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2)
  88
  89#define BITS2FREQ(x)    ((x) * FREQ_STEP - FREQ_IF)
  90
  91
  92struct maxiradio
  93{
  94        struct v4l2_device v4l2_dev;
  95        struct video_device vdev;
  96        struct pci_dev *pdev;
  97
  98        u16     io;     /* base of radio io */
  99        u16     muted;  /* VIDEO_AUDIO_MUTE */
 100        u16     stereo; /* VIDEO_TUNER_STEREO_ON */
 101        u16     tuned;  /* signal strength (0 or 0xffff) */
 102
 103        unsigned long freq;
 104
 105        struct mutex lock;
 106};
 107
 108static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
 109{
 110        return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
 111}
 112
 113static void outbit(unsigned long bit, u16 io)
 114{
 115        int val = power | wren | (bit ? data : 0);
 116
 117        outb(val, io);
 118        udelay(4);
 119        outb(val | clk, io);
 120        udelay(4);
 121        outb(val, io);
 122        udelay(4);
 123}
 124
 125static void turn_power(struct maxiradio *dev, int p)
 126{
 127        if (p != 0) {
 128                dprintk(dev, 1, "Radio powered on\n");
 129                outb(power, dev->io);
 130        } else {
 131                dprintk(dev, 1, "Radio powered off\n");
 132                outb(0, dev->io);
 133        }
 134}
 135
 136static void set_freq(struct maxiradio *dev, u32 freq)
 137{
 138        unsigned long int si;
 139        int bl;
 140        int io = dev->io;
 141        int val = FREQ2BITS(freq);
 142
 143        /* TEA5757 shift register bits (see pdf) */
 144
 145        outbit(0, io); /* 24  search */
 146        outbit(1, io); /* 23  search up/down */
 147
 148        outbit(0, io); /* 22  stereo/mono */
 149
 150        outbit(0, io); /* 21  band */
 151        outbit(0, io); /* 20  band (only 00=FM works I think) */
 152
 153        outbit(0, io); /* 19  port ? */
 154        outbit(0, io); /* 18  port ? */
 155
 156        outbit(0, io); /* 17  search level */
 157        outbit(0, io); /* 16  search level */
 158
 159        si = 0x8000;
 160        for (bl = 1; bl <= 16; bl++) {
 161                outbit(val & si, io);
 162                si >>= 1;
 163        }
 164
 165        dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n",
 166                                freq / 16000,
 167                                freq % 16000 * 100 / 16000);
 168
 169        turn_power(dev, 1);
 170}
 171
 172static int get_stereo(u16 io)
 173{
 174        outb(power,io);
 175        udelay(4);
 176
 177        return !(inb(io) & mo_st);
 178}
 179
 180static int get_tune(u16 io)
 181{
 182        outb(power+clk,io);
 183        udelay(4);
 184
 185        return !(inb(io) & mo_st);
 186}
 187
 188
 189static int vidioc_querycap(struct file *file, void  *priv,
 190                            struct v4l2_capability *v)
 191{
 192        struct maxiradio *dev = video_drvdata(file);
 193
 194        strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
 195        strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
 196        snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
 197        v->version = RADIO_VERSION;
 198        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 199        return 0;
 200}
 201
 202static int vidioc_g_tuner(struct file *file, void *priv,
 203                           struct v4l2_tuner *v)
 204{
 205        struct maxiradio *dev = video_drvdata(file);
 206
 207        if (v->index > 0)
 208                return -EINVAL;
 209
 210        mutex_lock(&dev->lock);
 211        strlcpy(v->name, "FM", sizeof(v->name));
 212        v->type = V4L2_TUNER_RADIO;
 213        v->rangelow = FREQ_LO;
 214        v->rangehigh = FREQ_HI;
 215        v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
 216        v->capability = V4L2_TUNER_CAP_LOW;
 217        if (get_stereo(dev->io))
 218                v->audmode = V4L2_TUNER_MODE_STEREO;
 219        else
 220                v->audmode = V4L2_TUNER_MODE_MONO;
 221        v->signal = 0xffff * get_tune(dev->io);
 222        mutex_unlock(&dev->lock);
 223
 224        return 0;
 225}
 226
 227static int vidioc_s_tuner(struct file *file, void *priv,
 228                           struct v4l2_tuner *v)
 229{
 230        return v->index ? -EINVAL : 0;
 231}
 232
 233static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 234{
 235        *i = 0;
 236        return 0;
 237}
 238
 239static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 240{
 241        return i ? -EINVAL : 0;
 242}
 243
 244static int vidioc_g_audio(struct file *file, void *priv,
 245                           struct v4l2_audio *a)
 246{
 247        a->index = 0;
 248        strlcpy(a->name, "Radio", sizeof(a->name));
 249        a->capability = V4L2_AUDCAP_STEREO;
 250        return 0;
 251}
 252
 253
 254static int vidioc_s_audio(struct file *file, void *priv,
 255                           struct v4l2_audio *a)
 256{
 257        return a->index ? -EINVAL : 0;
 258}
 259
 260static int vidioc_s_frequency(struct file *file, void *priv,
 261                               struct v4l2_frequency *f)
 262{
 263        struct maxiradio *dev = video_drvdata(file);
 264
 265        if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
 266                dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
 267                                        f->frequency / 16000,
 268                                        f->frequency % 16000 * 100 / 16000,
 269                                        FREQ_LO / 16000, FREQ_HI / 16000);
 270
 271                return -EINVAL;
 272        }
 273
 274        mutex_lock(&dev->lock);
 275        dev->freq = f->frequency;
 276        set_freq(dev, dev->freq);
 277        msleep(125);
 278        mutex_unlock(&dev->lock);
 279
 280        return 0;
 281}
 282
 283static int vidioc_g_frequency(struct file *file, void *priv,
 284                               struct v4l2_frequency *f)
 285{
 286        struct maxiradio *dev = video_drvdata(file);
 287
 288        f->type = V4L2_TUNER_RADIO;
 289        f->frequency = dev->freq;
 290
 291        dprintk(dev, 4, "radio freq is %d.%02d MHz",
 292                                f->frequency / 16000,
 293                                f->frequency % 16000 * 100 / 16000);
 294
 295        return 0;
 296}
 297
 298static int vidioc_queryctrl(struct file *file, void *priv,
 299                             struct v4l2_queryctrl *qc)
 300{
 301        switch (qc->id) {
 302        case V4L2_CID_AUDIO_MUTE:
 303                return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
 304        }
 305        return -EINVAL;
 306}
 307
 308static int vidioc_g_ctrl(struct file *file, void *priv,
 309                struct v4l2_control *ctrl)
 310{
 311        struct maxiradio *dev = video_drvdata(file);
 312
 313        switch (ctrl->id) {
 314        case V4L2_CID_AUDIO_MUTE:
 315                ctrl->value = dev->muted;
 316                return 0;
 317        }
 318
 319        return -EINVAL;
 320}
 321
 322static int vidioc_s_ctrl(struct file *file, void *priv,
 323                struct v4l2_control *ctrl)
 324{
 325        struct maxiradio *dev = video_drvdata(file);
 326
 327        switch (ctrl->id) {
 328        case V4L2_CID_AUDIO_MUTE:
 329                mutex_lock(&dev->lock);
 330                dev->muted = ctrl->value;
 331                if (dev->muted)
 332                        turn_power(dev, 0);
 333                else
 334                        set_freq(dev, dev->freq);
 335                mutex_unlock(&dev->lock);
 336                return 0;
 337        }
 338
 339        return -EINVAL;
 340}
 341
 342static const struct v4l2_file_operations maxiradio_fops = {
 343        .owner          = THIS_MODULE,
 344        .ioctl          = video_ioctl2,
 345};
 346
 347static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
 348        .vidioc_querycap    = vidioc_querycap,
 349        .vidioc_g_tuner     = vidioc_g_tuner,
 350        .vidioc_s_tuner     = vidioc_s_tuner,
 351        .vidioc_g_audio     = vidioc_g_audio,
 352        .vidioc_s_audio     = vidioc_s_audio,
 353        .vidioc_g_input     = vidioc_g_input,
 354        .vidioc_s_input     = vidioc_s_input,
 355        .vidioc_g_frequency = vidioc_g_frequency,
 356        .vidioc_s_frequency = vidioc_s_frequency,
 357        .vidioc_queryctrl   = vidioc_queryctrl,
 358        .vidioc_g_ctrl      = vidioc_g_ctrl,
 359        .vidioc_s_ctrl      = vidioc_s_ctrl,
 360};
 361
 362static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 363{
 364        struct maxiradio *dev;
 365        struct v4l2_device *v4l2_dev;
 366        int retval = -ENOMEM;
 367
 368        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 369        if (dev == NULL) {
 370                dev_err(&pdev->dev, "not enough memory\n");
 371                return -ENOMEM;
 372        }
 373
 374        v4l2_dev = &dev->v4l2_dev;
 375        mutex_init(&dev->lock);
 376        dev->pdev = pdev;
 377        dev->muted = 1;
 378        dev->freq = FREQ_LO;
 379
 380        strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
 381
 382        retval = v4l2_device_register(&pdev->dev, v4l2_dev);
 383        if (retval < 0) {
 384                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 385                goto errfr;
 386        }
 387
 388        if (!request_region(pci_resource_start(pdev, 0),
 389                           pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
 390                v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
 391                goto err_out;
 392        }
 393
 394        if (pci_enable_device(pdev))
 395                goto err_out_free_region;
 396
 397        dev->io = pci_resource_start(pdev, 0);
 398        strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
 399        dev->vdev.v4l2_dev = v4l2_dev;
 400        dev->vdev.fops = &maxiradio_fops;
 401        dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
 402        dev->vdev.release = video_device_release_empty;
 403        video_set_drvdata(&dev->vdev, dev);
 404
 405        if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
 406                v4l2_err(v4l2_dev, "can't register device!");
 407                goto err_out_free_region;
 408        }
 409
 410        v4l2_info(v4l2_dev, "version " DRIVER_VERSION
 411                        " time " __TIME__ "  " __DATE__ "\n");
 412
 413        v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
 414               dev->io);
 415        return 0;
 416
 417err_out_free_region:
 418        release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 419err_out:
 420        v4l2_device_unregister(v4l2_dev);
 421errfr:
 422        kfree(dev);
 423        return -ENODEV;
 424}
 425
 426static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
 427{
 428        struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
 429        struct maxiradio *dev = to_maxiradio(v4l2_dev);
 430
 431        video_unregister_device(&dev->vdev);
 432        v4l2_device_unregister(&dev->v4l2_dev);
 433        release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 434}
 435
 436static struct pci_device_id maxiradio_pci_tbl[] = {
 437        { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO,
 438                PCI_ANY_ID, PCI_ANY_ID, },
 439        { 0 }
 440};
 441
 442MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
 443
 444static struct pci_driver maxiradio_driver = {
 445        .name           = "radio-maxiradio",
 446        .id_table       = maxiradio_pci_tbl,
 447        .probe          = maxiradio_init_one,
 448        .remove         = __devexit_p(maxiradio_remove_one),
 449};
 450
 451static int __init maxiradio_radio_init(void)
 452{
 453        return pci_register_driver(&maxiradio_driver);
 454}
 455
 456static void __exit maxiradio_radio_exit(void)
 457{
 458        pci_unregister_driver(&maxiradio_driver);
 459}
 460
 461module_init(maxiradio_radio_init);
 462module_exit(maxiradio_radio_exit);
 463