diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-02-27 03:30:13 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-03-19 10:27:21 -0400 |
commit | d4ecc83b79cc290eadf1ffb33a589c3c72bbc295 (patch) | |
tree | 2f806d32d714a8481be13106649ad17ab1eb8c62 /sound/i2c/other/tea575x-tuner.c | |
parent | 9f1dfccf6607822f556698f0940ead57e6e42d5f (diff) |
[media] tea575x-tuner: update to latest V4L2 framework requirements
The tea575x-tuner module has been updated to use the latest V4L2 framework
functionality. This also required changes in the drivers that rely on it.
The tea575x changes are:
- The drivers must provide a v4l2_device struct to the tea module.
- The radio_nr module parameter must be part of the actual radio driver,
and not of the tea module.
- Changed the frequency range to the normal 76-108 MHz range instead of
50-150.
- Add hardware frequency seek support.
- Fix broken rxsubchans/audmode handling.
- The application can now select between stereo and mono.
- Support polling for control events.
- Add V4L2 priority handling.
And radio-sf16fmr2.c now uses the isa bus kernel framework.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Thanks-to: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'sound/i2c/other/tea575x-tuner.c')
-rw-r--r-- | sound/i2c/other/tea575x-tuner.c | 146 |
1 files changed, 80 insertions, 66 deletions
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 6b68c8206805..b291bd86c4ca 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c | |||
@@ -25,21 +25,20 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/version.h> | 28 | #include <linux/sched.h> |
29 | #include <media/v4l2-device.h> | ||
29 | #include <media/v4l2-dev.h> | 30 | #include <media/v4l2-dev.h> |
31 | #include <media/v4l2-fh.h> | ||
30 | #include <media/v4l2-ioctl.h> | 32 | #include <media/v4l2-ioctl.h> |
33 | #include <media/v4l2-event.h> | ||
31 | #include <sound/tea575x-tuner.h> | 34 | #include <sound/tea575x-tuner.h> |
32 | 35 | ||
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 36 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
34 | MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); | 37 | MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); |
35 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
36 | 39 | ||
37 | static int radio_nr = -1; | 40 | #define FREQ_LO (76U * 16000) |
38 | module_param(radio_nr, int, 0); | 41 | #define FREQ_HI (108U * 16000) |
39 | |||
40 | #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) | ||
41 | #define FREQ_LO (50UL * 16000) | ||
42 | #define FREQ_HI (150UL * 16000) | ||
43 | 42 | ||
44 | /* | 43 | /* |
45 | * definitions | 44 | * definitions |
@@ -121,28 +120,10 @@ static unsigned int snd_tea575x_read(struct snd_tea575x *tea) | |||
121 | return data; | 120 | return data; |
122 | } | 121 | } |
123 | 122 | ||
124 | static void snd_tea575x_get_freq(struct snd_tea575x *tea) | ||
125 | { | ||
126 | unsigned long freq; | ||
127 | |||
128 | freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; | ||
129 | /* freq *= 12.5 */ | ||
130 | freq *= 125; | ||
131 | freq /= 10; | ||
132 | /* crystal fixup */ | ||
133 | if (tea->tea5759) | ||
134 | freq += TEA575X_FMIF; | ||
135 | else | ||
136 | freq -= TEA575X_FMIF; | ||
137 | |||
138 | tea->freq = freq * 16; /* from kHz */ | ||
139 | } | ||
140 | |||
141 | static void snd_tea575x_set_freq(struct snd_tea575x *tea) | 123 | static void snd_tea575x_set_freq(struct snd_tea575x *tea) |
142 | { | 124 | { |
143 | unsigned long freq; | 125 | u32 freq = tea->freq; |
144 | 126 | ||
145 | freq = clamp(tea->freq, FREQ_LO, FREQ_HI); | ||
146 | freq /= 16; /* to kHz */ | 127 | freq /= 16; /* to kHz */ |
147 | /* crystal fixup */ | 128 | /* crystal fixup */ |
148 | if (tea->tea5759) | 129 | if (tea->tea5759) |
@@ -167,12 +148,14 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
167 | { | 148 | { |
168 | struct snd_tea575x *tea = video_drvdata(file); | 149 | struct snd_tea575x *tea = video_drvdata(file); |
169 | 150 | ||
170 | strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); | 151 | strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver)); |
171 | strlcpy(v->card, tea->card, sizeof(v->card)); | 152 | strlcpy(v->card, tea->card, sizeof(v->card)); |
172 | strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); | 153 | strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); |
173 | strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); | 154 | strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); |
174 | v->version = RADIO_VERSION; | 155 | v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; |
175 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; | 156 | if (!tea->cannot_read_data) |
157 | v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; | ||
158 | v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
176 | return 0; | 159 | return 0; |
177 | } | 160 | } |
178 | 161 | ||
@@ -191,18 +174,24 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
191 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | 174 | v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; |
192 | v->rangelow = FREQ_LO; | 175 | v->rangelow = FREQ_LO; |
193 | v->rangehigh = FREQ_HI; | 176 | v->rangehigh = FREQ_HI; |
194 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | 177 | v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; |
195 | v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; | 178 | v->audmode = (tea->val & TEA575X_BIT_MONO) ? |
179 | V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; | ||
196 | v->signal = tea->tuned ? 0xffff : 0; | 180 | v->signal = tea->tuned ? 0xffff : 0; |
197 | |||
198 | return 0; | 181 | return 0; |
199 | } | 182 | } |
200 | 183 | ||
201 | static int vidioc_s_tuner(struct file *file, void *priv, | 184 | static int vidioc_s_tuner(struct file *file, void *priv, |
202 | struct v4l2_tuner *v) | 185 | struct v4l2_tuner *v) |
203 | { | 186 | { |
204 | if (v->index > 0) | 187 | struct snd_tea575x *tea = video_drvdata(file); |
188 | |||
189 | if (v->index) | ||
205 | return -EINVAL; | 190 | return -EINVAL; |
191 | tea->val &= ~TEA575X_BIT_MONO; | ||
192 | if (v->audmode == V4L2_TUNER_MODE_MONO) | ||
193 | tea->val |= TEA575X_BIT_MONO; | ||
194 | snd_tea575x_write(tea, tea->val); | ||
206 | return 0; | 195 | return 0; |
207 | } | 196 | } |
208 | 197 | ||
@@ -214,7 +203,6 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
214 | if (f->tuner != 0) | 203 | if (f->tuner != 0) |
215 | return -EINVAL; | 204 | return -EINVAL; |
216 | f->type = V4L2_TUNER_RADIO; | 205 | f->type = V4L2_TUNER_RADIO; |
217 | snd_tea575x_get_freq(tea); | ||
218 | f->frequency = tea->freq; | 206 | f->frequency = tea->freq; |
219 | return 0; | 207 | return 0; |
220 | } | 208 | } |
@@ -227,32 +215,47 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
227 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) | 215 | if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) |
228 | return -EINVAL; | 216 | return -EINVAL; |
229 | 217 | ||
230 | if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) | 218 | tea->val &= ~TEA575X_BIT_SEARCH; |
231 | return -EINVAL; | 219 | tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI); |
232 | |||
233 | tea->freq = f->frequency; | ||
234 | |||
235 | snd_tea575x_set_freq(tea); | 220 | snd_tea575x_set_freq(tea); |
236 | |||
237 | return 0; | 221 | return 0; |
238 | } | 222 | } |
239 | 223 | ||
240 | static int vidioc_g_audio(struct file *file, void *priv, | 224 | static int vidioc_s_hw_freq_seek(struct file *file, void *fh, |
241 | struct v4l2_audio *a) | 225 | struct v4l2_hw_freq_seek *a) |
242 | { | 226 | { |
243 | if (a->index > 1) | 227 | struct snd_tea575x *tea = video_drvdata(file); |
244 | return -EINVAL; | ||
245 | |||
246 | strcpy(a->name, "Radio"); | ||
247 | a->capability = V4L2_AUDCAP_STEREO; | ||
248 | return 0; | ||
249 | } | ||
250 | 228 | ||
251 | static int vidioc_s_audio(struct file *file, void *priv, | 229 | if (tea->cannot_read_data) |
252 | struct v4l2_audio *a) | 230 | return -ENOTTY; |
253 | { | 231 | if (a->tuner || a->wrap_around) |
254 | if (a->index != 0) | ||
255 | return -EINVAL; | 232 | return -EINVAL; |
233 | tea->val |= TEA575X_BIT_SEARCH; | ||
234 | tea->val &= ~TEA575X_BIT_UPDOWN; | ||
235 | if (a->seek_upward) | ||
236 | tea->val |= TEA575X_BIT_UPDOWN; | ||
237 | snd_tea575x_write(tea, tea->val); | ||
238 | for (;;) { | ||
239 | unsigned val = snd_tea575x_read(tea); | ||
240 | |||
241 | if (!(val & TEA575X_BIT_SEARCH)) { | ||
242 | /* Found a frequency */ | ||
243 | val &= TEA575X_BIT_FREQ_MASK; | ||
244 | val = (val * 10) / 125; | ||
245 | if (tea->tea5759) | ||
246 | val += TEA575X_FMIF; | ||
247 | else | ||
248 | val -= TEA575X_FMIF; | ||
249 | tea->freq = clamp(val * 16, FREQ_LO, FREQ_HI); | ||
250 | return 0; | ||
251 | } | ||
252 | if (schedule_timeout_interruptible(msecs_to_jiffies(10))) { | ||
253 | /* some signal arrived, stop search */ | ||
254 | tea->val &= ~TEA575X_BIT_SEARCH; | ||
255 | snd_tea575x_write(tea, tea->val); | ||
256 | return -ERESTARTSYS; | ||
257 | } | ||
258 | } | ||
256 | return 0; | 259 | return 0; |
257 | } | 260 | } |
258 | 261 | ||
@@ -273,23 +276,27 @@ static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl) | |||
273 | static const struct v4l2_file_operations tea575x_fops = { | 276 | static const struct v4l2_file_operations tea575x_fops = { |
274 | .owner = THIS_MODULE, | 277 | .owner = THIS_MODULE, |
275 | .unlocked_ioctl = video_ioctl2, | 278 | .unlocked_ioctl = video_ioctl2, |
279 | .open = v4l2_fh_open, | ||
280 | .release = v4l2_fh_release, | ||
281 | .poll = v4l2_ctrl_poll, | ||
276 | }; | 282 | }; |
277 | 283 | ||
278 | static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { | 284 | static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { |
279 | .vidioc_querycap = vidioc_querycap, | 285 | .vidioc_querycap = vidioc_querycap, |
280 | .vidioc_g_tuner = vidioc_g_tuner, | 286 | .vidioc_g_tuner = vidioc_g_tuner, |
281 | .vidioc_s_tuner = vidioc_s_tuner, | 287 | .vidioc_s_tuner = vidioc_s_tuner, |
282 | .vidioc_g_audio = vidioc_g_audio, | ||
283 | .vidioc_s_audio = vidioc_s_audio, | ||
284 | .vidioc_g_frequency = vidioc_g_frequency, | 288 | .vidioc_g_frequency = vidioc_g_frequency, |
285 | .vidioc_s_frequency = vidioc_s_frequency, | 289 | .vidioc_s_frequency = vidioc_s_frequency, |
290 | .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, | ||
291 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
292 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
293 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
286 | }; | 294 | }; |
287 | 295 | ||
288 | static struct video_device tea575x_radio = { | 296 | static const struct video_device tea575x_radio = { |
289 | .name = "tea575x-tuner", | ||
290 | .fops = &tea575x_fops, | 297 | .fops = &tea575x_fops, |
291 | .ioctl_ops = &tea575x_ioctl_ops, | 298 | .ioctl_ops = &tea575x_ioctl_ops, |
292 | .release = video_device_release_empty, | 299 | .release = video_device_release_empty, |
293 | }; | 300 | }; |
294 | 301 | ||
295 | static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { | 302 | static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { |
@@ -303,11 +310,15 @@ int snd_tea575x_init(struct snd_tea575x *tea) | |||
303 | { | 310 | { |
304 | int retval; | 311 | int retval; |
305 | 312 | ||
306 | tea->mute = 1; | 313 | tea->mute = true; |
307 | 314 | ||
308 | snd_tea575x_write(tea, 0x55AA); | 315 | /* Not all devices can or know how to read the data back. |
309 | if (snd_tea575x_read(tea) != 0x55AA) | 316 | Such devices can set cannot_read_data to true. */ |
310 | return -ENODEV; | 317 | if (!tea->cannot_read_data) { |
318 | snd_tea575x_write(tea, 0x55AA); | ||
319 | if (snd_tea575x_read(tea) != 0x55AA) | ||
320 | return -ENODEV; | ||
321 | } | ||
311 | 322 | ||
312 | tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; | 323 | tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; |
313 | tea->freq = 90500 * 16; /* 90.5Mhz default */ | 324 | tea->freq = 90500 * 16; /* 90.5Mhz default */ |
@@ -316,14 +327,17 @@ int snd_tea575x_init(struct snd_tea575x *tea) | |||
316 | tea->vd = tea575x_radio; | 327 | tea->vd = tea575x_radio; |
317 | video_set_drvdata(&tea->vd, tea); | 328 | video_set_drvdata(&tea->vd, tea); |
318 | mutex_init(&tea->mutex); | 329 | mutex_init(&tea->mutex); |
330 | strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); | ||
319 | tea->vd.lock = &tea->mutex; | 331 | tea->vd.lock = &tea->mutex; |
332 | tea->vd.v4l2_dev = tea->v4l2_dev; | ||
333 | tea->vd.ctrl_handler = &tea->ctrl_handler; | ||
334 | set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags); | ||
320 | 335 | ||
321 | v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); | 336 | v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); |
322 | tea->vd.ctrl_handler = &tea->ctrl_handler; | ||
323 | v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | 337 | v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); |
324 | retval = tea->ctrl_handler.error; | 338 | retval = tea->ctrl_handler.error; |
325 | if (retval) { | 339 | if (retval) { |
326 | printk(KERN_ERR "tea575x-tuner: can't initialize controls\n"); | 340 | v4l2_err(tea->v4l2_dev, "can't initialize controls\n"); |
327 | v4l2_ctrl_handler_free(&tea->ctrl_handler); | 341 | v4l2_ctrl_handler_free(&tea->ctrl_handler); |
328 | return retval; | 342 | return retval; |
329 | } | 343 | } |
@@ -338,9 +352,9 @@ int snd_tea575x_init(struct snd_tea575x *tea) | |||
338 | 352 | ||
339 | v4l2_ctrl_handler_setup(&tea->ctrl_handler); | 353 | v4l2_ctrl_handler_setup(&tea->ctrl_handler); |
340 | 354 | ||
341 | retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr); | 355 | retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr); |
342 | if (retval) { | 356 | if (retval) { |
343 | printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); | 357 | v4l2_err(tea->v4l2_dev, "can't register video device!\n"); |
344 | v4l2_ctrl_handler_free(&tea->ctrl_handler); | 358 | v4l2_ctrl_handler_free(&tea->ctrl_handler); |
345 | return retval; | 359 | return retval; |
346 | } | 360 | } |