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