linux/drivers/media/radio/si470x/radio-si470x-common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  drivers/media/radio/si470x/radio-si470x-common.c
   4 *
   5 *  Driver for radios with Silicon Labs Si470x FM Radio Receivers
   6 *
   7 *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
   8 *  Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com>
   9 */
  10
  11
  12/*
  13 * History:
  14 * 2008-01-12   Tobias Lorenz <tobias.lorenz@gmx.net>
  15 *              Version 1.0.0
  16 *              - First working version
  17 * 2008-01-13   Tobias Lorenz <tobias.lorenz@gmx.net>
  18 *              Version 1.0.1
  19 *              - Improved error handling, every function now returns errno
  20 *              - Improved multi user access (start/mute/stop)
  21 *              - Channel doesn't get lost anymore after start/mute/stop
  22 *              - RDS support added (polling mode via interrupt EP 1)
  23 *              - marked default module parameters with *value*
  24 *              - switched from bit structs to bit masks
  25 *              - header file cleaned and integrated
  26 * 2008-01-14   Tobias Lorenz <tobias.lorenz@gmx.net>
  27 *              Version 1.0.2
  28 *              - hex values are now lower case
  29 *              - commented USB ID for ADS/Tech moved on todo list
  30 *              - blacklisted si470x in hid-quirks.c
  31 *              - rds buffer handling functions integrated into *_work, *_read
  32 *              - rds_command in si470x_poll exchanged against simple retval
  33 *              - check for firmware version 15
  34 *              - code order and prototypes still remain the same
  35 *              - spacing and bottom of band codes remain the same
  36 * 2008-01-16   Tobias Lorenz <tobias.lorenz@gmx.net>
  37 *              Version 1.0.3
  38 *              - code reordered to avoid function prototypes
  39 *              - switch/case defaults are now more user-friendly
  40 *              - unified comment style
  41 *              - applied all checkpatch.pl v1.12 suggestions
  42 *                except the warning about the too long lines with bit comments
  43 *              - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
  44 * 2008-01-22   Tobias Lorenz <tobias.lorenz@gmx.net>
  45 *              Version 1.0.4
  46 *              - avoid poss. locking when doing copy_to_user which may sleep
  47 *              - RDS is automatically activated on read now
  48 *              - code cleaned of unnecessary rds_commands
  49 *              - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
  50 *                (thanks to Guillaume RAMOUSSE)
  51 * 2008-01-27   Tobias Lorenz <tobias.lorenz@gmx.net>
  52 *              Version 1.0.5
  53 *              - number of seek_retries changed to tune_timeout
  54 *              - fixed problem with incomplete tune operations by own buffers
  55 *              - optimization of variables and printf types
  56 *              - improved error logging
  57 * 2008-01-31   Tobias Lorenz <tobias.lorenz@gmx.net>
  58 *              Oliver Neukum <oliver@neukum.org>
  59 *              Version 1.0.6
  60 *              - fixed coverity checker warnings in *_usb_driver_disconnect
  61 *              - probe()/open() race by correct ordering in probe()
  62 *              - DMA coherency rules by separate allocation of all buffers
  63 *              - use of endianness macros
  64 *              - abuse of spinlock, replaced by mutex
  65 *              - racy handling of timer in disconnect,
  66 *                replaced by delayed_work
  67 *              - racy interruptible_sleep_on(),
  68 *                replaced with wait_event_interruptible()
  69 *              - handle signals in read()
  70 * 2008-02-08   Tobias Lorenz <tobias.lorenz@gmx.net>
  71 *              Oliver Neukum <oliver@neukum.org>
  72 *              Version 1.0.7
  73 *              - usb autosuspend support
  74 *              - unplugging fixed
  75 * 2008-05-07   Tobias Lorenz <tobias.lorenz@gmx.net>
  76 *              Version 1.0.8
  77 *              - hardware frequency seek support
  78 *              - afc indication
  79 *              - more safety checks, let si470x_get_freq return errno
  80 *              - vidioc behavior corrected according to v4l2 spec
  81 * 2008-10-20   Alexey Klimov <klimov.linux@gmail.com>
  82 *              - add support for KWorld USB FM Radio FM700
  83 *              - blacklisted KWorld radio in hid-core.c and hid-ids.h
  84 * 2008-12-03   Mark Lord <mlord@pobox.com>
  85 *              - add support for DealExtreme USB Radio
  86 * 2009-01-31   Bob Ross <pigiron@gmx.com>
  87 *              - correction of stereo detection/setting
  88 *              - correction of signal strength indicator scaling
  89 * 2009-01-31   Rick Bronson <rick@efn.org>
  90 *              Tobias Lorenz <tobias.lorenz@gmx.net>
  91 *              - add LED status output
  92 *              - get HW/SW version from scratchpad
  93 * 2009-06-16   Edouard Lafargue <edouard@lafargue.name>
  94 *              Version 1.0.10
  95 *              - add support for interrupt mode for RDS endpoint,
  96 *                instead of polling.
  97 *                Improves RDS reception significantly
  98 */
  99
 100
 101/* kernel includes */
 102#include "radio-si470x.h"
 103
 104/**************************************************************************
 105 * Module Parameters
 106 **************************************************************************/
 107
 108/* Spacing (kHz) */
 109/* 0: 200 kHz (USA, Australia) */
 110/* 1: 100 kHz (Europe, Japan) */
 111/* 2:  50 kHz */
 112static unsigned short space = 2;
 113module_param(space, ushort, 0444);
 114MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
 115
 116/* De-emphasis */
 117/* 0: 75 us (USA) */
 118/* 1: 50 us (Europe, Australia, Japan) */
 119static unsigned short de = 1;
 120module_param(de, ushort, 0444);
 121MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
 122
 123/* Tune timeout */
 124static unsigned int tune_timeout = 3000;
 125module_param(tune_timeout, uint, 0644);
 126MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
 127
 128/* Seek timeout */
 129static unsigned int seek_timeout = 5000;
 130module_param(seek_timeout, uint, 0644);
 131MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
 132
 133static const struct v4l2_frequency_band bands[] = {
 134        {
 135                .type = V4L2_TUNER_RADIO,
 136                .index = 0,
 137                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 138                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
 139                            V4L2_TUNER_CAP_FREQ_BANDS |
 140                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 141                            V4L2_TUNER_CAP_HWSEEK_WRAP,
 142                .rangelow   =  87500 * 16,
 143                .rangehigh  = 108000 * 16,
 144                .modulation = V4L2_BAND_MODULATION_FM,
 145        },
 146        {
 147                .type = V4L2_TUNER_RADIO,
 148                .index = 1,
 149                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 150                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
 151                            V4L2_TUNER_CAP_FREQ_BANDS |
 152                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 153                            V4L2_TUNER_CAP_HWSEEK_WRAP,
 154                .rangelow   =  76000 * 16,
 155                .rangehigh  = 108000 * 16,
 156                .modulation = V4L2_BAND_MODULATION_FM,
 157        },
 158        {
 159                .type = V4L2_TUNER_RADIO,
 160                .index = 2,
 161                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 162                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
 163                            V4L2_TUNER_CAP_FREQ_BANDS |
 164                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 165                            V4L2_TUNER_CAP_HWSEEK_WRAP,
 166                .rangelow   =  76000 * 16,
 167                .rangehigh  =  90000 * 16,
 168                .modulation = V4L2_BAND_MODULATION_FM,
 169        },
 170};
 171
 172/**************************************************************************
 173 * Generic Functions
 174 **************************************************************************/
 175
 176/*
 177 * si470x_set_band - set the band
 178 */
 179static int si470x_set_band(struct si470x_device *radio, int band)
 180{
 181        if (radio->band == band)
 182                return 0;
 183
 184        radio->band = band;
 185        radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_BAND;
 186        radio->registers[SYSCONFIG2] |= radio->band << 6;
 187        return radio->set_register(radio, SYSCONFIG2);
 188}
 189
 190/*
 191 * si470x_set_chan - set the channel
 192 */
 193static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
 194{
 195        int retval;
 196        unsigned long time_left;
 197        bool timed_out = false;
 198
 199        retval = radio->get_register(radio, POWERCFG);
 200        if (retval)
 201                return retval;
 202
 203        if ((radio->registers[POWERCFG] & (POWERCFG_ENABLE|POWERCFG_DMUTE))
 204                != (POWERCFG_ENABLE|POWERCFG_DMUTE)) {
 205                return 0;
 206        }
 207
 208        /* start tuning */
 209        radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
 210        radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
 211        retval = radio->set_register(radio, CHANNEL);
 212        if (retval < 0)
 213                goto done;
 214
 215        /* wait till tune operation has completed */
 216        reinit_completion(&radio->completion);
 217        time_left = wait_for_completion_timeout(&radio->completion,
 218                                                msecs_to_jiffies(tune_timeout));
 219        if (time_left == 0)
 220                timed_out = true;
 221
 222        if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
 223                dev_warn(&radio->videodev.dev, "tune does not complete\n");
 224        if (timed_out)
 225                dev_warn(&radio->videodev.dev,
 226                        "tune timed out after %u ms\n", tune_timeout);
 227
 228        /* stop tuning */
 229        radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
 230        retval = radio->set_register(radio, CHANNEL);
 231
 232done:
 233        return retval;
 234}
 235
 236/*
 237 * si470x_get_step - get channel spacing
 238 */
 239static unsigned int si470x_get_step(struct si470x_device *radio)
 240{
 241        /* Spacing (kHz) */
 242        switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
 243        /* 0: 200 kHz (USA, Australia) */
 244        case 0:
 245                return 200 * 16;
 246        /* 1: 100 kHz (Europe, Japan) */
 247        case 1:
 248                return 100 * 16;
 249        /* 2:  50 kHz */
 250        default:
 251                return 50 * 16;
 252        }
 253}
 254
 255
 256/*
 257 * si470x_get_freq - get the frequency
 258 */
 259static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
 260{
 261        int chan, retval;
 262
 263        /* read channel */
 264        retval = radio->get_register(radio, READCHAN);
 265        chan = radio->registers[READCHAN] & READCHAN_READCHAN;
 266
 267        /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
 268        *freq = chan * si470x_get_step(radio) + bands[radio->band].rangelow;
 269
 270        return retval;
 271}
 272
 273
 274/*
 275 * si470x_set_freq - set the frequency
 276 */
 277int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
 278{
 279        unsigned short chan;
 280
 281        freq = clamp(freq, bands[radio->band].rangelow,
 282                           bands[radio->band].rangehigh);
 283        /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
 284        chan = (freq - bands[radio->band].rangelow) / si470x_get_step(radio);
 285
 286        return si470x_set_chan(radio, chan);
 287}
 288EXPORT_SYMBOL_GPL(si470x_set_freq);
 289
 290
 291/*
 292 * si470x_set_seek - set seek
 293 */
 294static int si470x_set_seek(struct si470x_device *radio,
 295                           const struct v4l2_hw_freq_seek *seek)
 296{
 297        int band, retval;
 298        unsigned int freq;
 299        bool timed_out = false;
 300        unsigned long time_left;
 301
 302        /* set band */
 303        if (seek->rangelow || seek->rangehigh) {
 304                for (band = 0; band < ARRAY_SIZE(bands); band++) {
 305                        if (bands[band].rangelow  == seek->rangelow &&
 306                            bands[band].rangehigh == seek->rangehigh)
 307                                break;
 308                }
 309                if (band == ARRAY_SIZE(bands))
 310                        return -EINVAL; /* No matching band found */
 311        } else
 312                band = 1; /* If nothing is specified seek 76 - 108 Mhz */
 313
 314        if (radio->band != band) {
 315                retval = si470x_get_freq(radio, &freq);
 316                if (retval)
 317                        return retval;
 318                retval = si470x_set_band(radio, band);
 319                if (retval)
 320                        return retval;
 321                retval = si470x_set_freq(radio, freq);
 322                if (retval)
 323                        return retval;
 324        }
 325
 326        /* start seeking */
 327        radio->registers[POWERCFG] |= POWERCFG_SEEK;
 328        if (seek->wrap_around)
 329                radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
 330        else
 331                radio->registers[POWERCFG] |= POWERCFG_SKMODE;
 332        if (seek->seek_upward)
 333                radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
 334        else
 335                radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
 336        retval = radio->set_register(radio, POWERCFG);
 337        if (retval < 0)
 338                return retval;
 339
 340        /* wait till tune operation has completed */
 341        reinit_completion(&radio->completion);
 342        time_left = wait_for_completion_timeout(&radio->completion,
 343                                                msecs_to_jiffies(seek_timeout));
 344        if (time_left == 0)
 345                timed_out = true;
 346
 347        if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
 348                dev_warn(&radio->videodev.dev, "seek does not complete\n");
 349        if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
 350                dev_warn(&radio->videodev.dev,
 351                        "seek failed / band limit reached\n");
 352
 353        /* stop seeking */
 354        radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
 355        retval = radio->set_register(radio, POWERCFG);
 356
 357        /* try again, if timed out */
 358        if (retval == 0 && timed_out)
 359                return -ENODATA;
 360        return retval;
 361}
 362
 363
 364/*
 365 * si470x_start - switch on radio
 366 */
 367int si470x_start(struct si470x_device *radio)
 368{
 369        int retval;
 370
 371        /* powercfg */
 372        radio->registers[POWERCFG] =
 373                POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
 374        retval = radio->set_register(radio, POWERCFG);
 375        if (retval < 0)
 376                goto done;
 377
 378        /* sysconfig 1 */
 379        radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN | SYSCONFIG1_STCIEN |
 380                                        SYSCONFIG1_RDS;
 381        radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
 382        radio->registers[SYSCONFIG1] |= SYSCONFIG1_GPIO2_INT;
 383        if (de)
 384                radio->registers[SYSCONFIG1] |= SYSCONFIG1_DE;
 385        retval = radio->set_register(radio, SYSCONFIG1);
 386        if (retval < 0)
 387                goto done;
 388
 389        /* sysconfig 2 */
 390        radio->registers[SYSCONFIG2] =
 391                (0x1f  << 8) |                          /* SEEKTH */
 392                ((radio->band << 6) & SYSCONFIG2_BAND) |/* BAND */
 393                ((space << 4) & SYSCONFIG2_SPACE) |     /* SPACE */
 394                15;                                     /* VOLUME (max) */
 395        retval = radio->set_register(radio, SYSCONFIG2);
 396        if (retval < 0)
 397                goto done;
 398
 399        /* reset last channel */
 400        retval = si470x_set_chan(radio,
 401                radio->registers[CHANNEL] & CHANNEL_CHAN);
 402
 403done:
 404        return retval;
 405}
 406EXPORT_SYMBOL_GPL(si470x_start);
 407
 408
 409/*
 410 * si470x_stop - switch off radio
 411 */
 412int si470x_stop(struct si470x_device *radio)
 413{
 414        int retval;
 415
 416        /* sysconfig 1 */
 417        radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
 418        retval = radio->set_register(radio, SYSCONFIG1);
 419        if (retval < 0)
 420                goto done;
 421
 422        /* powercfg */
 423        radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
 424        /* POWERCFG_ENABLE has to automatically go low */
 425        radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
 426        retval = radio->set_register(radio, POWERCFG);
 427
 428done:
 429        return retval;
 430}
 431EXPORT_SYMBOL_GPL(si470x_stop);
 432
 433
 434/*
 435 * si470x_rds_on - switch on rds reception
 436 */
 437static int si470x_rds_on(struct si470x_device *radio)
 438{
 439        int retval;
 440
 441        /* sysconfig 1 */
 442        radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
 443        retval = radio->set_register(radio, SYSCONFIG1);
 444        if (retval < 0)
 445                radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
 446
 447        return retval;
 448}
 449
 450
 451
 452/**************************************************************************
 453 * File Operations Interface
 454 **************************************************************************/
 455
 456/*
 457 * si470x_fops_read - read RDS data
 458 */
 459static ssize_t si470x_fops_read(struct file *file, char __user *buf,
 460                size_t count, loff_t *ppos)
 461{
 462        struct si470x_device *radio = video_drvdata(file);
 463        int retval = 0;
 464        unsigned int block_count = 0;
 465
 466        /* switch on rds reception */
 467        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 468                si470x_rds_on(radio);
 469
 470        /* block if no new data available */
 471        while (radio->wr_index == radio->rd_index) {
 472                if (file->f_flags & O_NONBLOCK) {
 473                        retval = -EWOULDBLOCK;
 474                        goto done;
 475                }
 476                if (wait_event_interruptible(radio->read_queue,
 477                        radio->wr_index != radio->rd_index) < 0) {
 478                        retval = -EINTR;
 479                        goto done;
 480                }
 481        }
 482
 483        /* calculate block count from byte count */
 484        count /= 3;
 485
 486        /* copy RDS block out of internal buffer and to user buffer */
 487        while (block_count < count) {
 488                if (radio->rd_index == radio->wr_index)
 489                        break;
 490
 491                /* always transfer rds complete blocks */
 492                if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
 493                        /* retval = -EFAULT; */
 494                        break;
 495
 496                /* increment and wrap read pointer */
 497                radio->rd_index += 3;
 498                if (radio->rd_index >= radio->buf_size)
 499                        radio->rd_index = 0;
 500
 501                /* increment counters */
 502                block_count++;
 503                buf += 3;
 504                retval += 3;
 505        }
 506
 507done:
 508        return retval;
 509}
 510
 511
 512/*
 513 * si470x_fops_poll - poll RDS data
 514 */
 515static __poll_t si470x_fops_poll(struct file *file,
 516                struct poll_table_struct *pts)
 517{
 518        struct si470x_device *radio = video_drvdata(file);
 519        __poll_t req_events = poll_requested_events(pts);
 520        __poll_t retval = v4l2_ctrl_poll(file, pts);
 521
 522        if (req_events & (EPOLLIN | EPOLLRDNORM)) {
 523                /* switch on rds reception */
 524                if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
 525                        si470x_rds_on(radio);
 526
 527                poll_wait(file, &radio->read_queue, pts);
 528
 529                if (radio->rd_index != radio->wr_index)
 530                        retval |= EPOLLIN | EPOLLRDNORM;
 531        }
 532
 533        return retval;
 534}
 535
 536
 537static int si470x_fops_open(struct file *file)
 538{
 539        struct si470x_device *radio = video_drvdata(file);
 540
 541        return radio->fops_open(file);
 542}
 543
 544
 545/*
 546 * si470x_fops_release - file release
 547 */
 548static int si470x_fops_release(struct file *file)
 549{
 550        struct si470x_device *radio = video_drvdata(file);
 551
 552        return radio->fops_release(file);
 553}
 554
 555
 556/*
 557 * si470x_fops - file operations interface
 558 */
 559static const struct v4l2_file_operations si470x_fops = {
 560        .owner                  = THIS_MODULE,
 561        .read                   = si470x_fops_read,
 562        .poll                   = si470x_fops_poll,
 563        .unlocked_ioctl         = video_ioctl2,
 564        .open                   = si470x_fops_open,
 565        .release                = si470x_fops_release,
 566};
 567
 568
 569
 570/**************************************************************************
 571 * Video4Linux Interface
 572 **************************************************************************/
 573
 574
 575static int si470x_s_ctrl(struct v4l2_ctrl *ctrl)
 576{
 577        struct si470x_device *radio =
 578                container_of(ctrl->handler, struct si470x_device, hdl);
 579
 580        switch (ctrl->id) {
 581        case V4L2_CID_AUDIO_VOLUME:
 582                radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
 583                radio->registers[SYSCONFIG2] |= ctrl->val;
 584                return radio->set_register(radio, SYSCONFIG2);
 585        case V4L2_CID_AUDIO_MUTE:
 586                if (ctrl->val)
 587                        radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
 588                else
 589                        radio->registers[POWERCFG] |= POWERCFG_DMUTE;
 590                return radio->set_register(radio, POWERCFG);
 591        default:
 592                return -EINVAL;
 593        }
 594}
 595
 596
 597/*
 598 * si470x_vidioc_g_tuner - get tuner attributes
 599 */
 600static int si470x_vidioc_g_tuner(struct file *file, void *priv,
 601                struct v4l2_tuner *tuner)
 602{
 603        struct si470x_device *radio = video_drvdata(file);
 604        int retval = 0;
 605
 606        if (tuner->index != 0)
 607                return -EINVAL;
 608
 609        if (!radio->status_rssi_auto_update) {
 610                retval = radio->get_register(radio, STATUSRSSI);
 611                if (retval < 0)
 612                        return retval;
 613        }
 614
 615        /* driver constants */
 616        strscpy(tuner->name, "FM", sizeof(tuner->name));
 617        tuner->type = V4L2_TUNER_RADIO;
 618        tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 619                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
 620                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
 621                            V4L2_TUNER_CAP_HWSEEK_WRAP;
 622        tuner->rangelow  =  76 * FREQ_MUL;
 623        tuner->rangehigh = 108 * FREQ_MUL;
 624
 625        /* stereo indicator == stereo (instead of mono) */
 626        if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
 627                tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
 628        else
 629                tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
 630        /* If there is a reliable method of detecting an RDS channel,
 631           then this code should check for that before setting this
 632           RDS subchannel. */
 633        tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
 634
 635        /* mono/stereo selector */
 636        if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
 637                tuner->audmode = V4L2_TUNER_MODE_STEREO;
 638        else
 639                tuner->audmode = V4L2_TUNER_MODE_MONO;
 640
 641        /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
 642        /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
 643        tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
 644        /* the ideal factor is 0xffff/75 = 873,8 */
 645        tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
 646        if (tuner->signal > 0xffff)
 647                tuner->signal = 0xffff;
 648
 649        /* automatic frequency control: -1: freq to low, 1 freq to high */
 650        /* AFCRL does only indicate that freq. differs, not if too low/high */
 651        tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
 652
 653        return retval;
 654}
 655
 656
 657/*
 658 * si470x_vidioc_s_tuner - set tuner attributes
 659 */
 660static int si470x_vidioc_s_tuner(struct file *file, void *priv,
 661                const struct v4l2_tuner *tuner)
 662{
 663        struct si470x_device *radio = video_drvdata(file);
 664
 665        if (tuner->index != 0)
 666                return -EINVAL;
 667
 668        /* mono/stereo selector */
 669        switch (tuner->audmode) {
 670        case V4L2_TUNER_MODE_MONO:
 671                radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
 672                break;
 673        case V4L2_TUNER_MODE_STEREO:
 674        default:
 675                radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
 676                break;
 677        }
 678
 679        return radio->set_register(radio, POWERCFG);
 680}
 681
 682
 683/*
 684 * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
 685 */
 686static int si470x_vidioc_g_frequency(struct file *file, void *priv,
 687                struct v4l2_frequency *freq)
 688{
 689        struct si470x_device *radio = video_drvdata(file);
 690
 691        if (freq->tuner != 0)
 692                return -EINVAL;
 693
 694        freq->type = V4L2_TUNER_RADIO;
 695        return si470x_get_freq(radio, &freq->frequency);
 696}
 697
 698
 699/*
 700 * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
 701 */
 702static int si470x_vidioc_s_frequency(struct file *file, void *priv,
 703                const struct v4l2_frequency *freq)
 704{
 705        struct si470x_device *radio = video_drvdata(file);
 706        int retval;
 707
 708        if (freq->tuner != 0)
 709                return -EINVAL;
 710
 711        if (freq->frequency < bands[radio->band].rangelow ||
 712            freq->frequency > bands[radio->band].rangehigh) {
 713                /* Switch to band 1 which covers everything we support */
 714                retval = si470x_set_band(radio, 1);
 715                if (retval)
 716                        return retval;
 717        }
 718        return si470x_set_freq(radio, freq->frequency);
 719}
 720
 721
 722/*
 723 * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
 724 */
 725static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
 726                const struct v4l2_hw_freq_seek *seek)
 727{
 728        struct si470x_device *radio = video_drvdata(file);
 729
 730        if (seek->tuner != 0)
 731                return -EINVAL;
 732
 733        if (file->f_flags & O_NONBLOCK)
 734                return -EWOULDBLOCK;
 735
 736        return si470x_set_seek(radio, seek);
 737}
 738
 739/*
 740 * si470x_vidioc_enum_freq_bands - enumerate supported bands
 741 */
 742static int si470x_vidioc_enum_freq_bands(struct file *file, void *priv,
 743                                         struct v4l2_frequency_band *band)
 744{
 745        if (band->tuner != 0)
 746                return -EINVAL;
 747        if (band->index >= ARRAY_SIZE(bands))
 748                return -EINVAL;
 749        *band = bands[band->index];
 750        return 0;
 751}
 752
 753const struct v4l2_ctrl_ops si470x_ctrl_ops = {
 754        .s_ctrl = si470x_s_ctrl,
 755};
 756EXPORT_SYMBOL_GPL(si470x_ctrl_ops);
 757
 758static int si470x_vidioc_querycap(struct file *file, void *priv,
 759                struct v4l2_capability *capability)
 760{
 761        struct si470x_device *radio = video_drvdata(file);
 762
 763        return radio->vidioc_querycap(file, priv, capability);
 764};
 765
 766/*
 767 * si470x_ioctl_ops - video device ioctl operations
 768 */
 769static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
 770        .vidioc_querycap        = si470x_vidioc_querycap,
 771        .vidioc_g_tuner         = si470x_vidioc_g_tuner,
 772        .vidioc_s_tuner         = si470x_vidioc_s_tuner,
 773        .vidioc_g_frequency     = si470x_vidioc_g_frequency,
 774        .vidioc_s_frequency     = si470x_vidioc_s_frequency,
 775        .vidioc_s_hw_freq_seek  = si470x_vidioc_s_hw_freq_seek,
 776        .vidioc_enum_freq_bands = si470x_vidioc_enum_freq_bands,
 777        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 778        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 779};
 780
 781
 782/*
 783 * si470x_viddev_template - video device interface
 784 */
 785const struct video_device si470x_viddev_template = {
 786        .fops                   = &si470x_fops,
 787        .name                   = DRIVER_NAME,
 788        .release                = video_device_release_empty,
 789        .ioctl_ops              = &si470x_ioctl_ops,
 790};
 791EXPORT_SYMBOL_GPL(si470x_viddev_template);
 792
 793MODULE_LICENSE("GPL");
 794