diff options
| author | Ingo Molnar <mingo@kernel.org> | 2012-04-14 13:18:27 +0200 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-04-14 13:19:04 +0200 |
| commit | 6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch) | |
| tree | 021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /sound/i2c | |
| parent | 682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff) | |
| parent | a385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff) | |
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree),
to prepare for tooling changes, and also to pick up v3.4 MM
changes that the uprobes code needs to take care of.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'sound/i2c')
| -rw-r--r-- | sound/i2c/other/tea575x-tuner.c | 169 |
1 files changed, 113 insertions, 56 deletions
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 6b68c8206805..a63faec5e7fd 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -25,21 +25,20 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> -#include <linux/version.h> +#include <linux/sched.h> +#include <media/v4l2-device.h> #include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <sound/tea575x-tuner.h> MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); MODULE_LICENSE("GPL"); -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) -#define FREQ_LO (50UL * 16000) -#define FREQ_HI (150UL * 16000) +#define FREQ_LO (76U * 16000) +#define FREQ_HI (108U * 16000) /* * definitions @@ -90,7 +89,7 @@ static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val) tea->ops->set_pins(tea, 0); } -static unsigned int snd_tea575x_read(struct snd_tea575x *tea) +static u32 snd_tea575x_read(struct snd_tea575x *tea) { u16 l, rdata; u32 data = 0; @@ -121,11 +120,13 @@ static unsigned int snd_tea575x_read(struct snd_tea575x *tea) return data; } -static void snd_tea575x_get_freq(struct snd_tea575x *tea) +static u32 snd_tea575x_get_freq(struct snd_tea575x *tea) { - unsigned long freq; + u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; + + if (freq == 0) + return freq; - freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; /* freq *= 12.5 */ freq *= 125; freq /= 10; @@ -135,14 +136,13 @@ static void snd_tea575x_get_freq(struct snd_tea575x *tea) else freq -= TEA575X_FMIF; - tea->freq = freq * 16; /* from kHz */ + return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */ } static void snd_tea575x_set_freq(struct snd_tea575x *tea) { - unsigned long freq; + u32 freq = tea->freq; - freq = clamp(tea->freq, FREQ_LO, FREQ_HI); freq /= 16; /* to kHz */ /* crystal fixup */ if (tea->tea5759) @@ -167,12 +167,14 @@ static int vidioc_querycap(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); - strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); + strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver)); strlcpy(v->card, tea->card, sizeof(v->card)); strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + if (!tea->cannot_read_data) + v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -191,18 +193,24 @@ static int vidioc_g_tuner(struct file *file, void *priv, v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; v->rangelow = FREQ_LO; v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; + v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + v->audmode = (tea->val & TEA575X_BIT_MONO) ? + V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; v->signal = tea->tuned ? 0xffff : 0; - return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) + struct snd_tea575x *tea = video_drvdata(file); + + if (v->index) return -EINVAL; + tea->val &= ~TEA575X_BIT_MONO; + if (v->audmode == V4L2_TUNER_MODE_MONO) + tea->val |= TEA575X_BIT_MONO; + snd_tea575x_write(tea, tea->val); return 0; } @@ -214,7 +222,6 @@ static int vidioc_g_frequency(struct file *file, void *priv, if (f->tuner != 0) return -EINVAL; f->type = V4L2_TUNER_RADIO; - snd_tea575x_get_freq(tea); f->frequency = tea->freq; return 0; } @@ -227,33 +234,72 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) - return -EINVAL; - - tea->freq = f->frequency; - + tea->val &= ~TEA575X_BIT_SEARCH; + tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI); snd_tea575x_set_freq(tea); - return 0; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_s_hw_freq_seek(struct file *file, void *fh, + struct v4l2_hw_freq_seek *a) { - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} + struct snd_tea575x *tea = video_drvdata(file); + unsigned long timeout; + int i; -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index != 0) + if (tea->cannot_read_data) + return -ENOTTY; + if (a->tuner || a->wrap_around) return -EINVAL; - return 0; + + /* clear the frequency, HW will fill it in */ + tea->val &= ~TEA575X_BIT_FREQ_MASK; + tea->val |= TEA575X_BIT_SEARCH; + if (a->seek_upward) + tea->val |= TEA575X_BIT_UPDOWN; + else + tea->val &= ~TEA575X_BIT_UPDOWN; + snd_tea575x_write(tea, tea->val); + timeout = jiffies + msecs_to_jiffies(10000); + for (;;) { + if (time_after(jiffies, timeout)) + break; + if (schedule_timeout_interruptible(msecs_to_jiffies(10))) { + /* some signal arrived, stop search */ + tea->val &= ~TEA575X_BIT_SEARCH; + snd_tea575x_set_freq(tea); + return -ERESTARTSYS; + } + if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) { + u32 freq; + + /* Found a frequency, wait until it can be read */ + for (i = 0; i < 100; i++) { + msleep(10); + freq = snd_tea575x_get_freq(tea); + if (freq) /* available */ + break; + } + if (freq == 0) /* shouldn't happen */ + break; + /* + * if we moved by less than 50 kHz, or in the wrong + * direction, continue seeking + */ + if (abs(tea->freq - freq) < 16 * 50 || + (a->seek_upward && freq < tea->freq) || + (!a->seek_upward && freq > tea->freq)) { + snd_tea575x_write(tea, tea->val); + continue; + } + tea->freq = freq; + tea->val &= ~TEA575X_BIT_SEARCH; + return 0; + } + } + tea->val &= ~TEA575X_BIT_SEARCH; + snd_tea575x_set_freq(tea); + return -EAGAIN; } static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl) @@ -273,23 +319,27 @@ static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl) static const struct v4l2_file_operations tea575x_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .poll = v4l2_ctrl_poll, }; static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device tea575x_radio = { - .name = "tea575x-tuner", +static const struct video_device tea575x_radio = { .fops = &tea575x_fops, .ioctl_ops = &tea575x_ioctl_ops, - .release = video_device_release_empty, + .release = video_device_release_empty, }; static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { @@ -303,27 +353,34 @@ int snd_tea575x_init(struct snd_tea575x *tea) { int retval; - tea->mute = 1; + tea->mute = true; - snd_tea575x_write(tea, 0x55AA); - if (snd_tea575x_read(tea) != 0x55AA) - return -ENODEV; + /* Not all devices can or know how to read the data back. + Such devices can set cannot_read_data to true. */ + if (!tea->cannot_read_data) { + snd_tea575x_write(tea, 0x55AA); + if (snd_tea575x_read(tea) != 0x55AA) + return -ENODEV; + } - tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; + tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28; tea->freq = 90500 * 16; /* 90.5Mhz default */ snd_tea575x_set_freq(tea); tea->vd = tea575x_radio; video_set_drvdata(&tea->vd, tea); mutex_init(&tea->mutex); + strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); tea->vd.lock = &tea->mutex; + tea->vd.v4l2_dev = tea->v4l2_dev; + tea->vd.ctrl_handler = &tea->ctrl_handler; + set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags); v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); - tea->vd.ctrl_handler = &tea->ctrl_handler; v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); retval = tea->ctrl_handler.error; if (retval) { - printk(KERN_ERR "tea575x-tuner: can't initialize controls\n"); + v4l2_err(tea->v4l2_dev, "can't initialize controls\n"); v4l2_ctrl_handler_free(&tea->ctrl_handler); return retval; } @@ -338,9 +395,9 @@ int snd_tea575x_init(struct snd_tea575x *tea) v4l2_ctrl_handler_setup(&tea->ctrl_handler); - retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr); + retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr); if (retval) { - printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); + v4l2_err(tea->v4l2_dev, "can't register video device!\n"); v4l2_ctrl_handler_free(&tea->ctrl_handler); return retval; } |
