diff options
author | Tobias Lorenz <tobias.lorenz@gmx.net> | 2008-05-31 14:11:32 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:08:43 -0400 |
commit | bbc8995f9fa3f9cdd77aeb7c9bbf5bf526feca3c (patch) | |
tree | 21e354bf284b7430e49ccd19abf1971f7ffc62fa /drivers/media/radio | |
parent | ace7d4bbe6170ef9b72bfa82c3e5769d250fffae (diff) |
V4L/DVB (7997): si470x: hardware frequency seek support
This patch brings the following changes:
- this now finally adds hardware frequency seek support
Signed-off-by: Tobias Lorenz <tobias.lorenz@gmx.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/radio')
-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 db9d64a228b..dc93a882b38 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 | ||