diff mbox

[1/3] tea575x: unify read/write functions

Message ID 201105092339.29143.linux@rainbow-software.org (mailing list archive)
State Not Applicable
Headers show

Commit Message

Ondrej Zary May 9, 2011, 9:39 p.m. UTC
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>

Comments

Takashi Iwai May 10, 2011, 7:38 a.m. UTC | #1
At Mon, 9 May 2011 23:39:26 +0200,
Ondrej Zary wrote:
> 
> 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>

Applied all three patches to sound git tree.  Thanks!


Takashi

> --- linux-2.6.39-rc2-/include/sound/tea575x-tuner.h	2011-04-29 22:48:34.000000000 +0200
> +++ linux-2.6.39-rc2/include/sound/tea575x-tuner.h	2011-05-06 22:20:46.000000000 +0200
> @@ -26,12 +26,17 @@
>  #include <media/v4l2-dev.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_ops {
> -	void (*write)(struct snd_tea575x *tea, unsigned int val);
> -	unsigned int (*read)(struct snd_tea575x *tea);
> -	void (*mute)(struct snd_tea575x *tea, unsigned int mute);
> +	void (*set_pins)(struct snd_tea575x *tea, u8 pins);
> +	u8 (*get_pins)(struct snd_tea575x *tea);
> +	void (*set_direction)(struct snd_tea575x *tea, bool output);
>  };
>  
>  struct snd_tea575x {
> @@ -49,7 +54,7 @@ struct snd_tea575x {
>  	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);
>  
>  #endif /* __SOUND_TEA575X_TUNER_H */
> --- linux-2.6.39-rc2-/sound/i2c/other/tea575x-tuner.c	2011-05-06 22:44:14.000000000 +0200
> +++ linux-2.6.39-rc2/sound/i2c/other/tea575x-tuner.c	2011-05-06 22:21:09.000000000 +0200
> @@ -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
>  
>  	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 *f
>  	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 *fi
>  
>  	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 *fi
>  
>  	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
>  	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
>  	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)
> 
> 
> -- 
> Ondrej Zary
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- linux-2.6.39-rc2-/include/sound/tea575x-tuner.h	2011-04-29 22:48:34.000000000 +0200
+++ linux-2.6.39-rc2/include/sound/tea575x-tuner.h	2011-05-06 22:20:46.000000000 +0200
@@ -26,12 +26,17 @@ 
 #include <media/v4l2-dev.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_ops {
-	void (*write)(struct snd_tea575x *tea, unsigned int val);
-	unsigned int (*read)(struct snd_tea575x *tea);
-	void (*mute)(struct snd_tea575x *tea, unsigned int mute);
+	void (*set_pins)(struct snd_tea575x *tea, u8 pins);
+	u8 (*get_pins)(struct snd_tea575x *tea);
+	void (*set_direction)(struct snd_tea575x *tea, bool output);
 };
 
 struct snd_tea575x {
@@ -49,7 +54,7 @@  struct snd_tea575x {
 	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);
 
 #endif /* __SOUND_TEA575X_TUNER_H */
--- linux-2.6.39-rc2-/sound/i2c/other/tea575x-tuner.c	2011-05-06 22:44:14.000000000 +0200
+++ linux-2.6.39-rc2/sound/i2c/other/tea575x-tuner.c	2011-05-06 22:21:09.000000000 +0200
@@ -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
 
 	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 *f
 	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 *fi
 
 	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 *fi
 
 	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
 	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
 	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)