Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14219d06 authored by Ondrej Zary's avatar Ondrej Zary Committed by Takashi Iwai
Browse files

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: default avatarOndrej Zary <linux@rainbow-software.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 59bb7f0e
Loading
Loading
Loading
Loading
+9 −4
Original line number Original line Diff line number Diff line
@@ -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 */
+72 −26
Original line number Original line Diff line number Diff line
@@ -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,11 +287,9 @@ 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)