From 375d135818f32bbe7b3f071bd54d977c4ff8d84a Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 19 Mar 2011 16:32:53 +0100 Subject: ALSA: tea575x-tuner: various improvements Improve tea575x-tuner with various good things from radio-maestro: - extend frequency range to 50-150MHz - fix querycap(): card name, CAP_RADIO - improve g_tuner(): CAP_STEREO, stereo and tuned indication - improve g_frequency(): tuner index checking and reading frequency from HW - improve s_frequency(): tuner index and type checking Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/tea575x-tuner.c | 52 ++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 14 deletions(-) (limited to 'sound/i2c') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index ee538f1ae846..9f35f378a17d 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -37,8 +37,8 @@ static int radio_nr = -1; module_param(radio_nr, int, 0); #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) -#define FREQ_LO (87 * 16000) -#define FREQ_HI (108 * 16000) +#define FREQ_LO (50UL * 16000) +#define FREQ_HI (150UL * 16000) /* * definitions @@ -77,15 +77,29 @@ static struct v4l2_queryctrl radio_qctrl[] = { * lowlevel part */ +static void snd_tea575x_get_freq(struct snd_tea575x *tea) +{ + unsigned long freq; + + freq = tea->ops->read(tea) & TEA575X_BIT_FREQ_MASK; + /* freq *= 12.5 */ + freq *= 125; + freq /= 10; + /* crystal fixup */ + if (tea->tea5759) + freq += tea->freq_fixup; + else + freq -= tea->freq_fixup; + + tea->freq = freq * 16; /* from kHz */ +} + static void snd_tea575x_set_freq(struct snd_tea575x *tea) { unsigned long freq; - freq = tea->freq / 16; /* to kHz */ - if (freq > 108000) - freq = 108000; - if (freq < 87000) - freq = 87000; + freq = clamp(tea->freq, FREQ_LO, FREQ_HI); + freq /= 16; /* to kHz */ /* crystal fixup */ if (tea->tea5759) freq -= tea->freq_fixup; @@ -109,29 +123,33 @@ static int vidioc_querycap(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); - strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757"); strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); - strlcpy(v->card, "Maestro Radio", sizeof(v->card)); + strlcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757", sizeof(v->card)); sprintf(v->bus_info, "PCI"); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct snd_tea575x *tea = video_drvdata(file); + if (v->index > 0) return -EINVAL; + tea->ops->read(tea); + strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; + 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->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; + v->signal = tea->tuned ? 0xffff : 0; + return 0; } @@ -148,7 +166,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; + snd_tea575x_get_freq(tea); f->frequency = tea->freq; return 0; } @@ -158,6 +179,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) return -EINVAL; -- cgit v1.2.3 From 1872f589951caee1afd7cd2ea6729ac892de9ddf Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 19 Mar 2011 16:33:14 +0100 Subject: ALSA: es1968: add radio (tea575x tuner) support Add TEA5757 radio tuner support to es1968 driver. This is found at least on MediaForte SF64-PCE2 sound cards. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/i2c') diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2dad40f3f622..c95d8f1aae87 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o -obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o +obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o -- cgit v1.2.3 From 14219d06592025541559027d0fd8f96ef75f313c Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 9 May 2011 23:39:26 +0200 Subject: ALSA: tea575x: unify read/write functions Implement generic read/write functions to access TEA575x tuners. They're now implemented 4 times (once in es1968 and 3 times in fm801). This also allows mute to work on all cards. Also improve tuner detection/initialization. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/tea575x-tuner.c | 98 ++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 26 deletions(-) (limited to 'sound/i2c') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 9f35f378a17d..31f9795daca6 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -77,11 +77,65 @@ static struct v4l2_queryctrl radio_qctrl[] = { * lowlevel part */ +static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val) +{ + u16 l; + u8 data; + + tea->ops->set_direction(tea, 1); + udelay(16); + + for (l = 25; l > 0; l--) { + data = (val >> 24) & TEA575X_DATA; + val <<= 1; /* shift data */ + tea->ops->set_pins(tea, data | TEA575X_WREN); + udelay(2); + tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK); + udelay(2); + tea->ops->set_pins(tea, data | TEA575X_WREN); + udelay(2); + } + + if (!tea->mute) + tea->ops->set_pins(tea, 0); +} + +static unsigned int snd_tea575x_read(struct snd_tea575x *tea) +{ + u16 l, rdata; + u32 data = 0; + + tea->ops->set_direction(tea, 0); + tea->ops->set_pins(tea, 0); + udelay(16); + + for (l = 24; l--;) { + tea->ops->set_pins(tea, TEA575X_CLK); + udelay(2); + if (!l) + tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1; + tea->ops->set_pins(tea, 0); + udelay(2); + data <<= 1; /* shift data */ + rdata = tea->ops->get_pins(tea); + if (!l) + tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1; + if (rdata & TEA575X_DATA) + data++; + udelay(2); + } + + if (tea->mute) + tea->ops->set_pins(tea, TEA575X_WREN); + + return data; +} + static void snd_tea575x_get_freq(struct snd_tea575x *tea) { unsigned long freq; - freq = tea->ops->read(tea) & TEA575X_BIT_FREQ_MASK; + freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; /* freq *= 12.5 */ freq *= 125; freq /= 10; @@ -111,7 +165,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea) tea->val &= ~TEA575X_BIT_FREQ_MASK; tea->val |= freq & TEA575X_BIT_FREQ_MASK; - tea->ops->write(tea, tea->val); + snd_tea575x_write(tea, tea->val); } /* @@ -139,7 +193,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (v->index > 0) return -EINVAL; - tea->ops->read(tea); + snd_tea575x_read(tea); strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; @@ -233,10 +287,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - ctrl->value = tea->mute; - return 0; - } + ctrl->value = tea->mute; + return 0; } return -EINVAL; } @@ -248,11 +300,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - tea->ops->mute(tea, ctrl->value); + if (tea->mute != ctrl->value) { tea->mute = ctrl->value; - return 0; + snd_tea575x_set_freq(tea); } + return 0; } return -EINVAL; } @@ -317,18 +369,16 @@ static struct video_device tea575x_radio = { /* * initialize all the tea575x chips */ -void snd_tea575x_init(struct snd_tea575x *tea) +int snd_tea575x_init(struct snd_tea575x *tea) { int retval; - unsigned int val; struct video_device *tea575x_radio_inst; - val = tea->ops->read(tea); - if (val == 0x1ffffff || val == 0) { - snd_printk(KERN_ERR - "tea575x-tuner: Cannot find TEA575x chip\n"); - return; - } + tea->mute = 1; + + snd_tea575x_write(tea, 0x55AA); + if (snd_tea575x_read(tea) != 0x55AA) + return -ENODEV; tea->in_use = 0; tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; @@ -337,7 +387,7 @@ void snd_tea575x_init(struct snd_tea575x *tea) tea575x_radio_inst = video_device_alloc(); if (tea575x_radio_inst == NULL) { printk(KERN_ERR "tea575x-tuner: not enough memory\n"); - return; + return -ENOMEM; } memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); @@ -352,17 +402,13 @@ void snd_tea575x_init(struct snd_tea575x *tea) if (retval) { printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); kfree(tea575x_radio_inst); - return; + return retval; } snd_tea575x_set_freq(tea); - - /* mute on init */ - if (tea->ops->mute) { - tea->ops->mute(tea, 1); - tea->mute = 1; - } tea->vd = tea575x_radio_inst; + + return 0; } void snd_tea575x_exit(struct snd_tea575x *tea) -- cgit v1.2.3 From ea27316e4cd13b25727715c0db8adb0b1661f5e7 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Thu, 12 May 2011 22:17:56 +0200 Subject: ALSA: tea575x: remove freq_fixup from struct freq_fixup is a constant, no need to hold it in struct snd_tea575x and set in each driver. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/tea575x-tuner.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/i2c') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 31f9795daca6..98ccec27e7bf 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -141,9 +141,9 @@ static void snd_tea575x_get_freq(struct snd_tea575x *tea) freq /= 10; /* crystal fixup */ if (tea->tea5759) - freq += tea->freq_fixup; + freq += TEA575X_FMIF; else - freq -= tea->freq_fixup; + freq -= TEA575X_FMIF; tea->freq = freq * 16; /* from kHz */ } @@ -156,9 +156,9 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea) freq /= 16; /* to kHz */ /* crystal fixup */ if (tea->tea5759) - freq -= tea->freq_fixup; + freq -= TEA575X_FMIF; else - freq += tea->freq_fixup; + freq += TEA575X_FMIF; /* freq /= 12.5 */ freq *= 10; freq /= 125; -- cgit v1.2.3 From 10ca72014741554ad37c149ff0d9e93c1e3d5b7d Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Thu, 12 May 2011 22:18:22 +0200 Subject: ALSA: tea575x: use better card and bus names Provide real card and bus_info instead of hardcoded values. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/tea575x-tuner.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/i2c') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 98ccec27e7bf..4831800239d3 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -178,8 +178,9 @@ 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->card, tea->tea5759 ? "TEA5759" : "TEA5757", sizeof(v->card)); - sprintf(v->bus_info, "PCI"); + 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; return 0; -- cgit v1.2.3