diff options
| -rw-r--r-- | drivers/media/radio/radio-si470x.c | 97 |
1 files changed, 95 insertions, 2 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index db9d64a228bb..dc93a882b385 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c | |||
| @@ -101,11 +101,11 @@ | |||
| 101 | * - unplugging fixed | 101 | * - unplugging fixed |
| 102 | * 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net> | 102 | * 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net> |
| 103 | * Version 1.0.8 | 103 | * Version 1.0.8 |
| 104 | * - hardware frequency seek support | ||
| 104 | * - afc indication | 105 | * - afc indication |
| 105 | * - more safety checks, let si470x_get_freq return errno | 106 | * - more safety checks, let si470x_get_freq return errno |
| 106 | * | 107 | * |
| 107 | * ToDo: | 108 | * ToDo: |
| 108 | * - add seeking support | ||
| 109 | * - add firmware download/update support | 109 | * - add firmware download/update support |
| 110 | * - RDS support: interrupt mode, instead of polling | 110 | * - RDS support: interrupt mode, instead of polling |
| 111 | * - add LED status output (check if that's not already done in firmware) | 111 | * - add LED status output (check if that's not already done in firmware) |
| @@ -192,6 +192,11 @@ static unsigned int tune_timeout = 3000; | |||
| 192 | module_param(tune_timeout, uint, 0); | 192 | module_param(tune_timeout, uint, 0); |
| 193 | MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); | 193 | MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); |
| 194 | 194 | ||
| 195 | /* Seek timeout */ | ||
| 196 | static unsigned int seek_timeout = 5000; | ||
| 197 | module_param(seek_timeout, uint, 0); | ||
| 198 | MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*"); | ||
| 199 | |||
| 195 | /* RDS buffer blocks */ | 200 | /* RDS buffer blocks */ |
| 196 | static unsigned int rds_buf = 100; | 201 | static unsigned int rds_buf = 100; |
| 197 | module_param(rds_buf, uint, 0); | 202 | module_param(rds_buf, uint, 0); |
| @@ -727,6 +732,62 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq) | |||
| 727 | 732 | ||
| 728 | 733 | ||
| 729 | /* | 734 | /* |
| 735 | * si470x_set_seek - set seek | ||
| 736 | */ | ||
| 737 | static int si470x_set_seek(struct si470x_device *radio, | ||
| 738 | unsigned int wrap_around, unsigned int seek_upward) | ||
| 739 | { | ||
| 740 | int retval = 0; | ||
| 741 | unsigned long timeout; | ||
| 742 | bool timed_out = 0; | ||
| 743 | |||
| 744 | /* start seeking */ | ||
| 745 | radio->registers[POWERCFG] |= POWERCFG_SEEK; | ||
| 746 | if (wrap_around == 1) | ||
| 747 | radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; | ||
| 748 | else | ||
| 749 | radio->registers[POWERCFG] |= POWERCFG_SKMODE; | ||
| 750 | if (seek_upward == 1) | ||
| 751 | radio->registers[POWERCFG] |= POWERCFG_SEEKUP; | ||
| 752 | else | ||
| 753 | radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; | ||
| 754 | retval = si470x_set_register(radio, POWERCFG); | ||
| 755 | if (retval < 0) | ||
| 756 | goto done; | ||
| 757 | |||
| 758 | /* wait till seek operation has completed */ | ||
| 759 | timeout = jiffies + msecs_to_jiffies(seek_timeout); | ||
| 760 | do { | ||
| 761 | retval = si470x_get_register(radio, STATUSRSSI); | ||
| 762 | if (retval < 0) | ||
| 763 | goto stop; | ||
| 764 | timed_out = time_after(jiffies, timeout); | ||
| 765 | } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && | ||
| 766 | (!timed_out)); | ||
| 767 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) | ||
| 768 | printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n"); | ||
| 769 | if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) | ||
| 770 | printk(KERN_WARNING DRIVER_NAME | ||
| 771 | ": seek failed / band limit reached\n"); | ||
| 772 | if (timed_out) | ||
| 773 | printk(KERN_WARNING DRIVER_NAME | ||
| 774 | ": seek timed out after %u ms\n", seek_timeout); | ||
| 775 | |||
| 776 | stop: | ||
| 777 | /* stop seeking */ | ||
| 778 | radio->registers[POWERCFG] &= ~POWERCFG_SEEK; | ||
| 779 | retval = si470x_set_register(radio, POWERCFG); | ||
| 780 | |||
| 781 | done: | ||
| 782 | /* try again, if timed out */ | ||
| 783 | if ((retval == 0) && timed_out) | ||
| 784 | retval = -EAGAIN; | ||
| 785 | |||
| 786 | return retval; | ||
| 787 | } | ||
| 788 | |||
| 789 | |||
| 790 | /* | ||
| 730 | * si470x_start - switch on radio | 791 | * si470x_start - switch on radio |
| 731 | */ | 792 | */ |
| 732 | static int si470x_start(struct si470x_device *radio) | 793 | static int si470x_start(struct si470x_device *radio) |
| @@ -1148,7 +1209,8 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, | |||
| 1148 | strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); | 1209 | strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); |
| 1149 | sprintf(capability->bus_info, "USB"); | 1210 | sprintf(capability->bus_info, "USB"); |
| 1150 | capability->version = DRIVER_KERNEL_VERSION; | 1211 | capability->version = DRIVER_KERNEL_VERSION; |
| 1151 | capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | 1212 | capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | |
| 1213 | V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
| 1152 | 1214 | ||
| 1153 | return 0; | 1215 | return 0; |
| 1154 | } | 1216 | } |
| @@ -1495,6 +1557,36 @@ done: | |||
| 1495 | 1557 | ||
| 1496 | 1558 | ||
| 1497 | /* | 1559 | /* |
| 1560 | * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek | ||
| 1561 | */ | ||
| 1562 | static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, | ||
| 1563 | struct v4l2_hw_freq_seek *seek) | ||
| 1564 | { | ||
| 1565 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | ||
| 1566 | int retval = 0; | ||
| 1567 | |||
| 1568 | /* safety checks */ | ||
| 1569 | if (radio->disconnected) { | ||
| 1570 | retval = -EIO; | ||
| 1571 | goto done; | ||
| 1572 | } | ||
| 1573 | if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) { | ||
| 1574 | retval = -EINVAL; | ||
| 1575 | goto done; | ||
| 1576 | } | ||
| 1577 | |||
| 1578 | retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); | ||
| 1579 | |||
| 1580 | done: | ||
| 1581 | if (retval < 0) | ||
| 1582 | printk(KERN_WARNING DRIVER_NAME | ||
| 1583 | ": set hardware frequency seek failed with %d\n", | ||
| 1584 | retval); | ||
| 1585 | return retval; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | |||
| 1589 | /* | ||
| 1498 | * si470x_viddev_tamples - video device interface | 1590 | * si470x_viddev_tamples - video device interface |
| 1499 | */ | 1591 | */ |
| 1500 | static struct video_device si470x_viddev_template = { | 1592 | static struct video_device si470x_viddev_template = { |
| @@ -1514,6 +1606,7 @@ static struct video_device si470x_viddev_template = { | |||
| 1514 | .vidioc_s_tuner = si470x_vidioc_s_tuner, | 1606 | .vidioc_s_tuner = si470x_vidioc_s_tuner, |
| 1515 | .vidioc_g_frequency = si470x_vidioc_g_frequency, | 1607 | .vidioc_g_frequency = si470x_vidioc_g_frequency, |
| 1516 | .vidioc_s_frequency = si470x_vidioc_s_frequency, | 1608 | .vidioc_s_frequency = si470x_vidioc_s_frequency, |
| 1609 | .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, | ||
| 1517 | .owner = THIS_MODULE, | 1610 | .owner = THIS_MODULE, |
| 1518 | }; | 1611 | }; |
| 1519 | 1612 | ||
