linux/drivers/media/video/saa6588.c
<<
>>
Prefs
   1/*
   2    Driver for SAA6588 RDS decoder
   3
   4    (c) 2005 Hans J. Koch
   5
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 2 of the License, or
   9    (at your option) any later version.
  10
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15
  16    You should have received a copy of the GNU General Public License
  17    along with this program; if not, write to the Free Software
  18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19*/
  20
  21
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/i2c.h>
  25#include <linux/types.h>
  26#include <linux/videodev2.h>
  27#include <linux/init.h>
  28#include <linux/errno.h>
  29#include <linux/slab.h>
  30#include <linux/poll.h>
  31#include <linux/wait.h>
  32#include <asm/uaccess.h>
  33
  34#include <media/saa6588.h>
  35#include <media/v4l2-device.h>
  36#include <media/v4l2-chip-ident.h>
  37
  38
  39/* insmod options */
  40static unsigned int debug;
  41static unsigned int xtal;
  42static unsigned int mmbs;
  43static unsigned int plvl;
  44static unsigned int bufblocks = 100;
  45
  46module_param(debug, int, 0644);
  47MODULE_PARM_DESC(debug, "enable debug messages");
  48module_param(xtal, int, 0);
  49MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
  50module_param(mmbs, int, 0);
  51MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
  52module_param(plvl, int, 0);
  53MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
  54module_param(bufblocks, int, 0);
  55MODULE_PARM_DESC(bufblocks, "number of buffered blocks, default 100");
  56
  57MODULE_DESCRIPTION("v4l2 driver module for SAA6588 RDS decoder");
  58MODULE_AUTHOR("Hans J. Koch <koch@hjk-az.de>");
  59
  60MODULE_LICENSE("GPL");
  61
  62/* ---------------------------------------------------------------------- */
  63
  64#define UNSET       (-1U)
  65#define PREFIX      "saa6588: "
  66#define dprintk     if (debug) printk
  67
  68struct saa6588 {
  69        struct v4l2_subdev sd;
  70        struct delayed_work work;
  71        spinlock_t lock;
  72        unsigned char *buffer;
  73        unsigned int buf_size;
  74        unsigned int rd_index;
  75        unsigned int wr_index;
  76        unsigned int block_count;
  77        unsigned char last_blocknum;
  78        wait_queue_head_t read_queue;
  79        int data_available_for_read;
  80        u8 sync;
  81};
  82
  83static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
  84{
  85        return container_of(sd, struct saa6588, sd);
  86}
  87
  88/* ---------------------------------------------------------------------- */
  89
  90/*
  91 * SAA6588 defines
  92 */
  93
  94/* Initialization and mode control byte (0w) */
  95
  96/* bit 0+1 (DAC0/DAC1) */
  97#define cModeStandard           0x00
  98#define cModeFastPI             0x01
  99#define cModeReducedRequest     0x02
 100#define cModeInvalid            0x03
 101
 102/* bit 2 (RBDS) */
 103#define cProcessingModeRDS      0x00
 104#define cProcessingModeRBDS     0x04
 105
 106/* bit 3+4 (SYM0/SYM1) */
 107#define cErrCorrectionNone      0x00
 108#define cErrCorrection2Bits     0x08
 109#define cErrCorrection5Bits     0x10
 110#define cErrCorrectionNoneRBDS  0x18
 111
 112/* bit 5 (NWSY) */
 113#define cSyncNormal             0x00
 114#define cSyncRestart            0x20
 115
 116/* bit 6 (TSQD) */
 117#define cSigQualityDetectOFF    0x00
 118#define cSigQualityDetectON     0x40
 119
 120/* bit 7 (SQCM) */
 121#define cSigQualityTriggered    0x00
 122#define cSigQualityContinous    0x80
 123
 124/* Pause level and flywheel control byte (1w) */
 125
 126/* bits 0..5 (FEB0..FEB5) */
 127#define cFlywheelMaxBlocksMask  0x3F
 128#define cFlywheelDefault        0x20
 129
 130/* bits 6+7 (PL0/PL1) */
 131#define cPauseLevel_11mV        0x00
 132#define cPauseLevel_17mV        0x40
 133#define cPauseLevel_27mV        0x80
 134#define cPauseLevel_43mV        0xC0
 135
 136/* Pause time/oscillator frequency/quality detector control byte (1w) */
 137
 138/* bits 0..4 (SQS0..SQS4) */
 139#define cQualityDetectSensMask  0x1F
 140#define cQualityDetectDefault   0x0F
 141
 142/* bit 5 (SOSC) */
 143#define cSelectOscFreqOFF       0x00
 144#define cSelectOscFreqON        0x20
 145
 146/* bit 6+7 (PTF0/PTF1) */
 147#define cOscFreq_4332kHz        0x00
 148#define cOscFreq_8664kHz        0x40
 149#define cOscFreq_12996kHz       0x80
 150#define cOscFreq_17328kHz       0xC0
 151
 152/* ---------------------------------------------------------------------- */
 153
 154static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
 155{
 156        int i;
 157
 158        if (s->rd_index == s->wr_index) {
 159                if (debug > 2)
 160                        dprintk(PREFIX "Read: buffer empty.\n");
 161                return 0;
 162        }
 163
 164        if (debug > 2) {
 165                dprintk(PREFIX "Read: ");
 166                for (i = s->rd_index; i < s->rd_index + 3; i++)
 167                        dprintk("0x%02x ", s->buffer[i]);
 168        }
 169
 170        if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3))
 171                return -EFAULT;
 172
 173        s->rd_index += 3;
 174        if (s->rd_index >= s->buf_size)
 175                s->rd_index = 0;
 176        s->block_count--;
 177
 178        if (debug > 2)
 179                dprintk("%d blocks total.\n", s->block_count);
 180
 181        return 1;
 182}
 183
 184static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
 185{
 186        unsigned long flags;
 187
 188        unsigned char __user *buf_ptr = a->buffer;
 189        unsigned int i;
 190        unsigned int rd_blocks;
 191
 192        a->result = 0;
 193        if (!a->buffer)
 194                return;
 195
 196        while (!s->data_available_for_read) {
 197                int ret = wait_event_interruptible(s->read_queue,
 198                                             s->data_available_for_read);
 199                if (ret == -ERESTARTSYS) {
 200                        a->result = -EINTR;
 201                        return;
 202                }
 203        }
 204
 205        spin_lock_irqsave(&s->lock, flags);
 206        rd_blocks = a->block_count;
 207        if (rd_blocks > s->block_count)
 208                rd_blocks = s->block_count;
 209
 210        if (!rd_blocks) {
 211                spin_unlock_irqrestore(&s->lock, flags);
 212                return;
 213        }
 214
 215        for (i = 0; i < rd_blocks; i++) {
 216                if (block_to_user_buf(s, buf_ptr)) {
 217                        buf_ptr += 3;
 218                        a->result++;
 219                } else
 220                        break;
 221        }
 222        a->result *= 3;
 223        s->data_available_for_read = (s->block_count > 0);
 224        spin_unlock_irqrestore(&s->lock, flags);
 225}
 226
 227static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
 228{
 229        unsigned int i;
 230
 231        if (debug > 3)
 232                dprintk(PREFIX "New block: ");
 233
 234        for (i = 0; i < 3; ++i) {
 235                if (debug > 3)
 236                        dprintk("0x%02x ", blockbuf[i]);
 237                s->buffer[s->wr_index] = blockbuf[i];
 238                s->wr_index++;
 239        }
 240
 241        if (s->wr_index >= s->buf_size)
 242                s->wr_index = 0;
 243
 244        if (s->wr_index == s->rd_index) {
 245                s->rd_index += 3;
 246                if (s->rd_index >= s->buf_size)
 247                        s->rd_index = 0;
 248        } else
 249                s->block_count++;
 250
 251        if (debug > 3)
 252                dprintk("%d blocks total.\n", s->block_count);
 253}
 254
 255static void saa6588_i2c_poll(struct saa6588 *s)
 256{
 257        struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
 258        unsigned long flags;
 259        unsigned char tmpbuf[6];
 260        unsigned char blocknum;
 261        unsigned char tmp;
 262
 263        /* Although we only need 3 bytes, we have to read at least 6.
 264           SAA6588 returns garbage otherwise. */
 265        if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
 266                if (debug > 1)
 267                        dprintk(PREFIX "read error!\n");
 268                return;
 269        }
 270
 271        s->sync = tmpbuf[0] & 0x10;
 272        if (!s->sync)
 273                return;
 274        blocknum = tmpbuf[0] >> 5;
 275        if (blocknum == s->last_blocknum) {
 276                if (debug > 3)
 277                        dprintk("Saw block %d again.\n", blocknum);
 278                return;
 279        }
 280
 281        s->last_blocknum = blocknum;
 282
 283        /*
 284           Byte order according to v4l2 specification:
 285
 286           Byte 0: Least Significant Byte of RDS Block
 287           Byte 1: Most Significant Byte of RDS Block
 288           Byte 2 Bit 7: Error bit. Indicates that an uncorrectable error
 289           occurred during reception of this block.
 290           Bit 6: Corrected bit. Indicates that an error was
 291           corrected for this data block.
 292           Bits 5-3: Same as bits 0-2.
 293           Bits 2-0: Block number.
 294
 295           SAA6588 byte order is Status-MSB-LSB, so we have to swap the
 296           first and the last of the 3 bytes block.
 297         */
 298
 299        tmp = tmpbuf[2];
 300        tmpbuf[2] = tmpbuf[0];
 301        tmpbuf[0] = tmp;
 302
 303        /* Map 'Invalid block E' to 'Invalid Block' */
 304        if (blocknum == 6)
 305                blocknum = V4L2_RDS_BLOCK_INVALID;
 306        /* And if are not in mmbs mode, then 'Block E' is also mapped
 307           to 'Invalid Block'. As far as I can tell MMBS is discontinued,
 308           and if there is ever a need to support E blocks, then please
 309           contact the linux-media mailinglist. */
 310        else if (!mmbs && blocknum == 5)
 311                blocknum = V4L2_RDS_BLOCK_INVALID;
 312        tmp = blocknum;
 313        tmp |= blocknum << 3;   /* Received offset == Offset Name (OK ?) */
 314        if ((tmpbuf[2] & 0x03) == 0x03)
 315                tmp |= V4L2_RDS_BLOCK_ERROR;     /* uncorrectable error */
 316        else if ((tmpbuf[2] & 0x03) != 0x00)
 317                tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
 318        tmpbuf[2] = tmp;        /* Is this enough ? Should we also check other bits ? */
 319
 320        spin_lock_irqsave(&s->lock, flags);
 321        block_to_buf(s, tmpbuf);
 322        spin_unlock_irqrestore(&s->lock, flags);
 323        s->data_available_for_read = 1;
 324        wake_up_interruptible(&s->read_queue);
 325}
 326
 327static void saa6588_work(struct work_struct *work)
 328{
 329        struct saa6588 *s = container_of(work, struct saa6588, work.work);
 330
 331        saa6588_i2c_poll(s);
 332        schedule_delayed_work(&s->work, msecs_to_jiffies(20));
 333}
 334
 335static void saa6588_configure(struct saa6588 *s)
 336{
 337        struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
 338        unsigned char buf[3];
 339        int rc;
 340
 341        buf[0] = cSyncRestart;
 342        if (mmbs)
 343                buf[0] |= cProcessingModeRBDS;
 344
 345        buf[1] = cFlywheelDefault;
 346        switch (plvl) {
 347        case 0:
 348                buf[1] |= cPauseLevel_11mV;
 349                break;
 350        case 1:
 351                buf[1] |= cPauseLevel_17mV;
 352                break;
 353        case 2:
 354                buf[1] |= cPauseLevel_27mV;
 355                break;
 356        case 3:
 357                buf[1] |= cPauseLevel_43mV;
 358                break;
 359        default:                /* nothing */
 360                break;
 361        }
 362
 363        buf[2] = cQualityDetectDefault | cSelectOscFreqON;
 364
 365        switch (xtal) {
 366        case 0:
 367                buf[2] |= cOscFreq_4332kHz;
 368                break;
 369        case 1:
 370                buf[2] |= cOscFreq_8664kHz;
 371                break;
 372        case 2:
 373                buf[2] |= cOscFreq_12996kHz;
 374                break;
 375        case 3:
 376                buf[2] |= cOscFreq_17328kHz;
 377                break;
 378        default:                /* nothing */
 379                break;
 380        }
 381
 382        dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
 383                buf[0], buf[1], buf[2]);
 384
 385        rc = i2c_master_send(client, buf, 3);
 386        if (rc != 3)
 387                printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
 388}
 389
 390/* ---------------------------------------------------------------------- */
 391
 392static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 393{
 394        struct saa6588 *s = to_saa6588(sd);
 395        struct saa6588_command *a = arg;
 396
 397        switch (cmd) {
 398                /* --- open() for /dev/radio --- */
 399        case SAA6588_CMD_OPEN:
 400                a->result = 0;  /* return error if chip doesn't work ??? */
 401                break;
 402                /* --- close() for /dev/radio --- */
 403        case SAA6588_CMD_CLOSE:
 404                s->data_available_for_read = 1;
 405                wake_up_interruptible(&s->read_queue);
 406                a->result = 0;
 407                break;
 408                /* --- read() for /dev/radio --- */
 409        case SAA6588_CMD_READ:
 410                read_from_buf(s, a);
 411                break;
 412                /* --- poll() for /dev/radio --- */
 413        case SAA6588_CMD_POLL:
 414                a->result = 0;
 415                if (s->data_available_for_read) {
 416                        a->result |= POLLIN | POLLRDNORM;
 417                }
 418                poll_wait(a->instance, &s->read_queue, a->event_list);
 419                break;
 420
 421        default:
 422                /* nothing */
 423                return -ENOIOCTLCMD;
 424        }
 425        return 0;
 426}
 427
 428static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 429{
 430        struct saa6588 *s = to_saa6588(sd);
 431
 432        vt->capability |= V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
 433        if (s->sync)
 434                vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
 435        return 0;
 436}
 437
 438static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 439{
 440        struct saa6588 *s = to_saa6588(sd);
 441
 442        saa6588_configure(s);
 443        return 0;
 444}
 445
 446static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 447{
 448        struct i2c_client *client = v4l2_get_subdevdata(sd);
 449
 450        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA6588, 0);
 451}
 452
 453/* ----------------------------------------------------------------------- */
 454
 455static const struct v4l2_subdev_core_ops saa6588_core_ops = {
 456        .g_chip_ident = saa6588_g_chip_ident,
 457        .ioctl = saa6588_ioctl,
 458};
 459
 460static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
 461        .g_tuner = saa6588_g_tuner,
 462        .s_tuner = saa6588_s_tuner,
 463};
 464
 465static const struct v4l2_subdev_ops saa6588_ops = {
 466        .core = &saa6588_core_ops,
 467        .tuner = &saa6588_tuner_ops,
 468};
 469
 470/* ---------------------------------------------------------------------- */
 471
 472static int saa6588_probe(struct i2c_client *client,
 473                         const struct i2c_device_id *id)
 474{
 475        struct saa6588 *s;
 476        struct v4l2_subdev *sd;
 477
 478        v4l_info(client, "saa6588 found @ 0x%x (%s)\n",
 479                        client->addr << 1, client->adapter->name);
 480
 481        s = kzalloc(sizeof(*s), GFP_KERNEL);
 482        if (s == NULL)
 483                return -ENOMEM;
 484
 485        s->buf_size = bufblocks * 3;
 486
 487        s->buffer = kmalloc(s->buf_size, GFP_KERNEL);
 488        if (s->buffer == NULL) {
 489                kfree(s);
 490                return -ENOMEM;
 491        }
 492        sd = &s->sd;
 493        v4l2_i2c_subdev_init(sd, client, &saa6588_ops);
 494        spin_lock_init(&s->lock);
 495        s->block_count = 0;
 496        s->wr_index = 0;
 497        s->rd_index = 0;
 498        s->last_blocknum = 0xff;
 499        init_waitqueue_head(&s->read_queue);
 500        s->data_available_for_read = 0;
 501
 502        saa6588_configure(s);
 503
 504        /* start polling via eventd */
 505        INIT_DELAYED_WORK(&s->work, saa6588_work);
 506        schedule_delayed_work(&s->work, 0);
 507        return 0;
 508}
 509
 510static int saa6588_remove(struct i2c_client *client)
 511{
 512        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 513        struct saa6588 *s = to_saa6588(sd);
 514
 515        v4l2_device_unregister_subdev(sd);
 516
 517        cancel_delayed_work_sync(&s->work);
 518
 519        kfree(s->buffer);
 520        kfree(s);
 521        return 0;
 522}
 523
 524/* ----------------------------------------------------------------------- */
 525
 526static const struct i2c_device_id saa6588_id[] = {
 527        { "saa6588", 0 },
 528        { }
 529};
 530MODULE_DEVICE_TABLE(i2c, saa6588_id);
 531
 532static struct i2c_driver saa6588_driver = {
 533        .driver = {
 534                .owner  = THIS_MODULE,
 535                .name   = "saa6588",
 536        },
 537        .probe          = saa6588_probe,
 538        .remove         = saa6588_remove,
 539        .id_table       = saa6588_id,
 540};
 541
 542static __init int init_saa6588(void)
 543{
 544        return i2c_add_driver(&saa6588_driver);
 545}
 546
 547static __exit void exit_saa6588(void)
 548{
 549        i2c_del_driver(&saa6588_driver);
 550}
 551
 552module_init(init_saa6588);
 553module_exit(exit_saa6588);
 554