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; 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 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; break; 286 /* 1: 76 - 108 MHz (Japan wide band) */ 287 default: 288 band_bottom = 76 * FREQ_MUL; break; 289 /* 2: 76 - 90 MHz (Japan) */ 290 case 2: 291 band_bottom = 76 * FREQ_MUL; break; 292 }; 293 294 /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ 295 chan = (freq - band_bottom) / spacing; 296 297 return si470x_set_chan(radio, chan); 298 } 299 300 301 /* 302 * si470x_set_seek - set seek 303 */ 304 static int si470x_set_seek(struct si470x_device *radio, 305 unsigned int wrap_around, unsigned int seek_upward) 306 { 307 int retval = 0; 308 unsigned long timeout; 309 bool timed_out = 0; 310 311 /* start seeking */ 312 radio->registers[POWERCFG] |= POWERCFG_SEEK; 313 if (wrap_around == 1) 314 radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; 315 else 316 radio->registers[POWERCFG] |= POWERCFG_SKMODE; 317 if (seek_upward == 1) 318 radio->registers[POWERCFG] |= POWERCFG_SEEKUP; 319 else 320 radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; 321 retval = si470x_set_register(radio, POWERCFG); 322 if (retval < 0) 323 goto done; 324 325 /* currently I2C driver only uses interrupt way to seek */ 326 if (radio->stci_enabled) { 327 INIT_COMPLETION(radio->completion); 328 329 /* wait till seek operation has completed */ 330 retval = wait_for_completion_timeout(&radio->completion, 331 msecs_to_jiffies(seek_timeout)); 332 if (!retval) 333 timed_out = true; 334 } else { 335 /* wait till seek operation has completed */ 336 timeout = jiffies + msecs_to_jiffies(seek_timeout); 337 do { 338 retval = si470x_get_register(radio, STATUSRSSI); 339 if (retval < 0) 340 goto stop; 341 timed_out = time_after(jiffies, timeout); 342 } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) 343 && (!timed_out)); 344 } 345 346 if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) 347 dev_warn(&radio->videodev->dev, "seek does not complete\n"); 348 if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) 349 dev_warn(&radio->videodev->dev, 350 "seek failed / band limit reached\n"); 351 if (timed_out) 352 dev_warn(&radio->videodev->dev, 353 "seek timed out after %u ms\n", seek_timeout); 354 355 stop: 356 /* stop seeking */ 357 radio->registers[POWERCFG] &= ~POWERCFG_SEEK; 358 retval = si470x_set_register(radio, POWERCFG); 359 360 done: 361 /* try again, if timed out */ 362 if ((retval == 0) && timed_out) 363 retval = -EAGAIN; 364 365 return retval; 366 } 367 368 369 /* 370 * si470x_start - switch on radio 371 */ 372 int si470x_start(struct si470x_device *radio) 373 { 374 int retval; 375 376 /* powercfg */ 377 radio->registers[POWERCFG] = 378 POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; 379 retval = si470x_set_register(radio, POWERCFG); 380 if (retval < 0) 381 goto done; 382 383 /* sysconfig 1 */ 384 radio->registers[SYSCONFIG1] = 385 (de << 11) & SYSCONFIG1_DE; /* DE*/ 386 retval = si470x_set_register(radio, SYSCONFIG1); 387 if (retval < 0) 388 goto done; 389 390 /* sysconfig 2 */ 391 radio->registers[SYSCONFIG2] = 392 (0x3f << 8) | /* SEEKTH */ 393 ((band << 6) & SYSCONFIG2_BAND) | /* BAND */ 394 ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */ 395 15; /* VOLUME (max) */ 396 retval = si470x_set_register(radio, SYSCONFIG2); 397 if (retval < 0) 398 goto done; 399 400 /* reset last channel */ 401 retval = si470x_set_chan(radio, 402 radio->registers[CHANNEL] & CHANNEL_CHAN); 403 404 done: 405 return retval; 406 } 407 408 409 /* 410 * si470x_stop - switch off radio 411 */ 412 int si470x_stop(struct si470x_device *radio) 413 { 414 int retval; 415 416 /* sysconfig 1 */ 417 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; 418 retval = si470x_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 = si470x_set_register(radio, POWERCFG); 427 428 done: 429 return retval; 430 } 431 432 433 /* 434 * si470x_rds_on - switch on rds reception 435 */ 436 static int si470x_rds_on(struct si470x_device *radio) 437 { 438 int retval; 439 440 /* sysconfig 1 */ 441 radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; 442 retval = si470x_set_register(radio, SYSCONFIG1); 443 if (retval < 0) 444 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; 445 446 return retval; 447 } 448 449 450 451 /************************************************************************** 452 * File Operations Interface 453 **************************************************************************/ 454 455 /* 456 * si470x_fops_read - read RDS data 457 */ 458 static ssize_t si470x_fops_read(struct file *file, char __user *buf, 459 size_t count, loff_t *ppos) 460 { 461 struct si470x_device *radio = video_drvdata(file); 462 int retval = 0; 463 unsigned int block_count = 0; 464 465 /* switch on rds reception */ 466 mutex_lock(&radio->lock); 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 507 done: 508 mutex_unlock(&radio->lock); 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 int retval = 0; 521 522 /* switch on rds reception */ 523 524 mutex_lock(&radio->lock); 525 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) 526 si470x_rds_on(radio); 527 mutex_unlock(&radio->lock); 528 529 poll_wait(file, &radio->read_queue, pts); 530 531 if (radio->rd_index != radio->wr_index) 532 retval = POLLIN | POLLRDNORM; 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 * si470x_vidioc_queryctrl - enumerate control items 558 */ 559 static int si470x_vidioc_queryctrl(struct file *file, void *priv, 560 struct v4l2_queryctrl *qc) 561 { 562 struct si470x_device *radio = video_drvdata(file); 563 int retval = -EINVAL; 564 565 /* abort if qc->id is below V4L2_CID_BASE */ 566 if (qc->id < V4L2_CID_BASE) 567 goto done; 568 569 /* search video control */ 570 switch (qc->id) { 571 case V4L2_CID_AUDIO_VOLUME: 572 return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15); 573 case V4L2_CID_AUDIO_MUTE: 574 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); 575 } 576 577 /* disable unsupported base controls */ 578 /* to satisfy kradio and such apps */ 579 if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) { 580 qc->flags = V4L2_CTRL_FLAG_DISABLED; 581 retval = 0; 582 } 583 584 done: 585 if (retval < 0) 586 dev_warn(&radio->videodev->dev, 587 "query controls failed with %d\n", retval); 588 return retval; 589 } 590 591 592 /* 593 * si470x_vidioc_g_ctrl - get the value of a control 594 */ 595 static int si470x_vidioc_g_ctrl(struct file *file, void *priv, 596 struct v4l2_control *ctrl) 597 { 598 struct si470x_device *radio = video_drvdata(file); 599 int retval = 0; 600 601 mutex_lock(&radio->lock); 602 /* safety checks */ 603 retval = si470x_disconnect_check(radio); 604 if (retval) 605 goto done; 606 607 switch (ctrl->id) { 608 case V4L2_CID_AUDIO_VOLUME: 609 ctrl->value = radio->registers[SYSCONFIG2] & 610 SYSCONFIG2_VOLUME; 611 break; 612 case V4L2_CID_AUDIO_MUTE: 613 ctrl->value = ((radio->registers[POWERCFG] & 614 POWERCFG_DMUTE) == 0) ? 1 : 0; 615 break; 616 default: 617 retval = -EINVAL; 618 } 619 620 done: 621 if (retval < 0) 622 dev_warn(&radio->videodev->dev, 623 "get control failed with %d\n", retval); 624 625 mutex_unlock(&radio->lock); 626 return retval; 627 } 628 629 630 /* 631 * si470x_vidioc_s_ctrl - set the value of a control 632 */ 633 static int si470x_vidioc_s_ctrl(struct file *file, void *priv, 634 struct v4l2_control *ctrl) 635 { 636 struct si470x_device *radio = video_drvdata(file); 637 int retval = 0; 638 639 mutex_lock(&radio->lock); 640 /* safety checks */ 641 retval = si470x_disconnect_check(radio); 642 if (retval) 643 goto done; 644 645 switch (ctrl->id) { 646 case V4L2_CID_AUDIO_VOLUME: 647 radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; 648 radio->registers[SYSCONFIG2] |= ctrl->value; 649 retval = si470x_set_register(radio, SYSCONFIG2); 650 break; 651 case V4L2_CID_AUDIO_MUTE: 652 if (ctrl->value == 1) 653 radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; 654 else 655 radio->registers[POWERCFG] |= POWERCFG_DMUTE; 656 retval = si470x_set_register(radio, POWERCFG); 657 break; 658 default: 659 retval = -EINVAL; 660 } 661 662 done: 663 if (retval < 0) 664 dev_warn(&radio->videodev->dev, 665 "set control failed with %d\n", retval); 666 mutex_unlock(&radio->lock); 667 return retval; 668 } 669 670 671 /* 672 * si470x_vidioc_g_audio - get audio attributes 673 */ 674 static int si470x_vidioc_g_audio(struct file *file, void *priv, 675 struct v4l2_audio *audio) 676 { 677 /* driver constants */ 678 audio->index = 0; 679 strcpy(audio->name, "Radio"); 680 audio->capability = V4L2_AUDCAP_STEREO; 681 audio->mode = 0; 682 683 return 0; 684 } 685 686 687 /* 688 * si470x_vidioc_g_tuner - get tuner attributes 689 */ 690 static int si470x_vidioc_g_tuner(struct file *file, void *priv, 691 struct v4l2_tuner *tuner) 692 { 693 struct si470x_device *radio = video_drvdata(file); 694 int retval = 0; 695 696 mutex_lock(&radio->lock); 697 /* safety checks */ 698 retval = si470x_disconnect_check(radio); 699 if (retval) 700 goto done; 701 702 if (tuner->index != 0) { 703 retval = -EINVAL; 704 goto done; 705 } 706 707 retval = si470x_get_register(radio, STATUSRSSI); 708 if (retval < 0) 709 goto done; 710 711 /* driver constants */ 712 strcpy(tuner->name, "FM"); 713 tuner->type = V4L2_TUNER_RADIO; 714 tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | 715 V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; 716 717 /* range limits */ 718 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { 719 /* 0: 87.5 - 108 MHz (USA, Europe, default) */ 720 default: 721 tuner->rangelow = 87.5 * FREQ_MUL; 722 tuner->rangehigh = 108 * FREQ_MUL; 723 break; 724 /* 1: 76 - 108 MHz (Japan wide band) */ 725 case 1: 726 tuner->rangelow = 76 * FREQ_MUL; 727 tuner->rangehigh = 108 * FREQ_MUL; 728 break; 729 /* 2: 76 - 90 MHz (Japan) */ 730 case 2: 731 tuner->rangelow = 76 * FREQ_MUL; 732 tuner->rangehigh = 90 * FREQ_MUL; 733 break; 734 }; 735 736 /* stereo indicator == stereo (instead of mono) */ 737 if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) 738 tuner->rxsubchans = V4L2_TUNER_SUB_MONO; 739 else 740 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 741 /* If there is a reliable method of detecting an RDS channel, 742 then this code should check for that before setting this 743 RDS subchannel. */ 744 tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; 745 746 /* mono/stereo selector */ 747 if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) 748 tuner->audmode = V4L2_TUNER_MODE_STEREO; 749 else 750 tuner->audmode = V4L2_TUNER_MODE_MONO; 751 752 /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ 753 /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */ 754 tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); 755 /* the ideal factor is 0xffff/75 = 873,8 */ 756 tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); 757 758 /* automatic frequency control: -1: freq to low, 1 freq to high */ 759 /* AFCRL does only indicate that freq. differs, not if too low/high */ 760 tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0; 761 762 done: 763 if (retval < 0) 764 dev_warn(&radio->videodev->dev, 765 "get tuner failed with %d\n", retval); 766 mutex_unlock(&radio->lock); 767 return retval; 768 } 769 770 771 /* 772 * si470x_vidioc_s_tuner - set tuner attributes 773 */ 774 static int si470x_vidioc_s_tuner(struct file *file, void *priv, 775 struct v4l2_tuner *tuner) 776 { 777 struct si470x_device *radio = video_drvdata(file); 778 int retval = 0; 779 780 mutex_lock(&radio->lock); 781 /* safety checks */ 782 retval = si470x_disconnect_check(radio); 783 if (retval) 784 goto done; 785 786 if (tuner->index != 0) 787 goto done; 788 789 /* mono/stereo selector */ 790 switch (tuner->audmode) { 791 case V4L2_TUNER_MODE_MONO: 792 radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ 793 break; 794 case V4L2_TUNER_MODE_STEREO: 795 radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ 796 break; 797 default: 798 goto done; 799 } 800 801 retval = si470x_set_register(radio, POWERCFG); 802 803 done: 804 if (retval < 0) 805 dev_warn(&radio->videodev->dev, 806 "set tuner failed with %d\n", retval); 807 mutex_unlock(&radio->lock); 808 return retval; 809 } 810 811 812 /* 813 * si470x_vidioc_g_frequency - get tuner or modulator radio frequency 814 */ 815 static int si470x_vidioc_g_frequency(struct file *file, void *priv, 816 struct v4l2_frequency *freq) 817 { 818 struct si470x_device *radio = video_drvdata(file); 819 int retval = 0; 820 821 /* safety checks */ 822 mutex_lock(&radio->lock); 823 retval = si470x_disconnect_check(radio); 824 if (retval) 825 goto done; 826 827 if (freq->tuner != 0) { 828 retval = -EINVAL; 829 goto done; 830 } 831 832 freq->type = V4L2_TUNER_RADIO; 833 retval = si470x_get_freq(radio, &freq->frequency); 834 835 done: 836 if (retval < 0) 837 dev_warn(&radio->videodev->dev, 838 "get frequency failed with %d\n", retval); 839 mutex_unlock(&radio->lock); 840 return retval; 841 } 842 843 844 /* 845 * si470x_vidioc_s_frequency - set tuner or modulator radio frequency 846 */ 847 static int si470x_vidioc_s_frequency(struct file *file, void *priv, 848 struct v4l2_frequency *freq) 849 { 850 struct si470x_device *radio = video_drvdata(file); 851 int retval = 0; 852 853 mutex_lock(&radio->lock); 854 /* safety checks */ 855 retval = si470x_disconnect_check(radio); 856 if (retval) 857 goto done; 858 859 if (freq->tuner != 0) { 860 retval = -EINVAL; 861 goto done; 862 } 863 864 retval = si470x_set_freq(radio, freq->frequency); 865 866 done: 867 if (retval < 0) 868 dev_warn(&radio->videodev->dev, 869 "set frequency failed with %d\n", retval); 870 mutex_unlock(&radio->lock); 871 return retval; 872 } 873 874 875 /* 876 * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek 877 */ 878 static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, 879 struct v4l2_hw_freq_seek *seek) 880 { 881 struct si470x_device *radio = video_drvdata(file); 882 int retval = 0; 883 884 mutex_lock(&radio->lock); 885 /* safety checks */ 886 retval = si470x_disconnect_check(radio); 887 if (retval) 888 goto done; 889 890 if (seek->tuner != 0) { 891 retval = -EINVAL; 892 goto done; 893 } 894 895 retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); 896 897 done: 898 if (retval < 0) 899 dev_warn(&radio->videodev->dev, 900 "set hardware frequency seek failed with %d\n", retval); 901 mutex_unlock(&radio->lock); 902 return retval; 903 } 904 905 906 /* 907 * si470x_ioctl_ops - video device ioctl operations 908 */ 909 static const struct v4l2_ioctl_ops si470x_ioctl_ops = { 910 .vidioc_querycap = si470x_vidioc_querycap, 911 .vidioc_queryctrl = si470x_vidioc_queryctrl, 912 .vidioc_g_ctrl = si470x_vidioc_g_ctrl, 913 .vidioc_s_ctrl = si470x_vidioc_s_ctrl, 914 .vidioc_g_audio = si470x_vidioc_g_audio, 915 .vidioc_g_tuner = si470x_vidioc_g_tuner, 916 .vidioc_s_tuner = si470x_vidioc_s_tuner, 917 .vidioc_g_frequency = si470x_vidioc_g_frequency, 918 .vidioc_s_frequency = si470x_vidioc_s_frequency, 919 .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, 920 }; 921 922 923 /* 924 * si470x_viddev_template - video device interface 925 */ 926 struct video_device si470x_viddev_template = { 927 .fops = &si470x_fops, 928 .name = DRIVER_NAME, 929 .release = video_device_release, 930 .ioctl_ops = &si470x_ioctl_ops, 931 }; 932