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 <linux@rainbow-software.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Ondrej Zary 2011-05-09 23:39:26 +02:00 committed by Takashi Iwai
parent 59bb7f0eeb
commit 14219d0659
2 changed files with 81 additions and 30 deletions

View file

@ -26,12 +26,17 @@
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#define TEA575X_DATA (1 << 0)
#define TEA575X_CLK (1 << 1)
#define TEA575X_WREN (1 << 2)
#define TEA575X_MOST (1 << 3)
struct snd_tea575x; struct snd_tea575x;
struct snd_tea575x_ops { struct snd_tea575x_ops {
void (*write)(struct snd_tea575x *tea, unsigned int val); void (*set_pins)(struct snd_tea575x *tea, u8 pins);
unsigned int (*read)(struct snd_tea575x *tea); u8 (*get_pins)(struct snd_tea575x *tea);
void (*mute)(struct snd_tea575x *tea, unsigned int mute); void (*set_direction)(struct snd_tea575x *tea, bool output);
}; };
struct snd_tea575x { struct snd_tea575x {
@ -49,7 +54,7 @@ struct snd_tea575x {
void *private_data; void *private_data;
}; };
void snd_tea575x_init(struct snd_tea575x *tea); int snd_tea575x_init(struct snd_tea575x *tea);
void snd_tea575x_exit(struct snd_tea575x *tea); void snd_tea575x_exit(struct snd_tea575x *tea);
#endif /* __SOUND_TEA575X_TUNER_H */ #endif /* __SOUND_TEA575X_TUNER_H */

View file

@ -77,11 +77,65 @@ static struct v4l2_queryctrl radio_qctrl[] = {
* lowlevel part * 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) static void snd_tea575x_get_freq(struct snd_tea575x *tea)
{ {
unsigned long freq; 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 *= 12.5 */
freq *= 125; freq *= 125;
freq /= 10; freq /= 10;
@ -111,7 +165,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea)
tea->val &= ~TEA575X_BIT_FREQ_MASK; tea->val &= ~TEA575X_BIT_FREQ_MASK;
tea->val |= freq & 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) if (v->index > 0)
return -EINVAL; return -EINVAL;
tea->ops->read(tea); snd_tea575x_read(tea);
strcpy(v->name, "FM"); strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO; v->type = V4L2_TUNER_RADIO;
@ -233,10 +287,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_MUTE:
if (tea->ops->mute) { ctrl->value = tea->mute;
ctrl->value = tea->mute; return 0;
return 0;
}
} }
return -EINVAL; return -EINVAL;
} }
@ -248,11 +300,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_MUTE:
if (tea->ops->mute) { if (tea->mute != ctrl->value) {
tea->ops->mute(tea, ctrl->value);
tea->mute = ctrl->value; tea->mute = ctrl->value;
return 0; snd_tea575x_set_freq(tea);
} }
return 0;
} }
return -EINVAL; return -EINVAL;
} }
@ -317,18 +369,16 @@ static struct video_device tea575x_radio = {
/* /*
* initialize all the tea575x chips * initialize all the tea575x chips
*/ */
void snd_tea575x_init(struct snd_tea575x *tea) int snd_tea575x_init(struct snd_tea575x *tea)
{ {
int retval; int retval;
unsigned int val;
struct video_device *tea575x_radio_inst; struct video_device *tea575x_radio_inst;
val = tea->ops->read(tea); tea->mute = 1;
if (val == 0x1ffffff || val == 0) {
snd_printk(KERN_ERR snd_tea575x_write(tea, 0x55AA);
"tea575x-tuner: Cannot find TEA575x chip\n"); if (snd_tea575x_read(tea) != 0x55AA)
return; return -ENODEV;
}
tea->in_use = 0; tea->in_use = 0;
tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; 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(); tea575x_radio_inst = video_device_alloc();
if (tea575x_radio_inst == NULL) { if (tea575x_radio_inst == NULL) {
printk(KERN_ERR "tea575x-tuner: not enough memory\n"); printk(KERN_ERR "tea575x-tuner: not enough memory\n");
return; return -ENOMEM;
} }
memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
@ -352,17 +402,13 @@ void snd_tea575x_init(struct snd_tea575x *tea)
if (retval) { if (retval) {
printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
kfree(tea575x_radio_inst); kfree(tea575x_radio_inst);
return; return retval;
} }
snd_tea575x_set_freq(tea); 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; tea->vd = tea575x_radio_inst;
return 0;
} }
void snd_tea575x_exit(struct snd_tea575x *tea) void snd_tea575x_exit(struct snd_tea575x *tea)