Re: cx25840: improve audio for cx2388x drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Em 14-01-2012 16:44, Miroslav Slugeň escreveu:
> Searching for testers, this patch is big one, it was more then week of
> work and testing, so i appriciate any comments and recommendations.
> 
> 
> cx25840_audio_fixes.patch
> 
> 
> Signed-off-by: Miroslav Slugen <thunder.mmm@xxxxxxxxx>
> From: Miroslav Slugen <thunder.mmm@xxxxxxxxx>
> Date: Mon, 12 Dec 2011 00:19:34 +0100
> Subject: [PATCH] This patch should fix many analog audio issues for cx23885 based cards.
> 
> 1. Rewrite part of set_input to cx25840_audio_set_path, this part should be
>  set only when soft reset is asserted and microcontroler is stopped.
>  
> 2. While using AUDIO6 and AUDIO7 inputs we should always stop microcontroler,
>  because they are not tuner inputs, this should fix no-audio for composite
>  s-video and componnet input on many types of tuners.
> 
> 3. Add radio_deemphasis support, in Europe we use 50us, with 75us sound is not so cool.
> 
> 4. Add audio_standard_force support. On many types of cards autodetection of
>  audio standard just doesn't work, my research in this shows that it could be
>  just in wrong registers settings or in detection algorithm, so if we want to
>  have audio on such broken tuners we have to force audio standard, this is done
>  in input_change and should not introduce any regression, i tested this behavior
>  on card with working autodetection Leadtek DVR3200H_xc4000 and with not working
>  DVR3200H_xc3028, first card has audio even with previouse code, but xc3028
>  (older model) has no audio, to get audio support it require to set AUD_STANDARD
>  register, of course forced mode is available in driver level (pvr150_workaround)
>  or as option to module.
>  
> 5. Improve format detection as writen in cx25840 datasheet, this is done in
>  cx23885_initialize and in input_change functions.
>  In init it is necesary to reset tuner autodetection and tuner.
>  In input change i just add others formats from datasheet, previouse code was
>  just for NTSC detection, and it is also necesary to reset microcontroler, but
>  only if it is running.


Your Signed-off-by: is missing on this patch.

> 
> ---
> diff -Naurp a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
> --- a/drivers/media/video/cx25840/cx25840-audio.c	2012-01-05 00:55:44.000000000 +0100
> +++ b/drivers/media/video/cx25840/cx25840-audio.c	2012-01-14 16:05:38.616366747 +0100
> @@ -446,14 +446,45 @@ void cx25840_audio_set_path(struct i2c_c
>  
>  		/* Mute everything to prevent the PFFT! */
>  		cx25840_write(client, 0x8d3, 0x1f);
> +		cx25840_write(client, 0x8e3, 0x03);
>  
> -		if (state->aud_input == CX25840_AUDIO_SERIAL) {
> +		if (is_cx231xx(state) || is_cx2388x(state)) {
> +			/* Path1 require different GPIO0 pin mux */
> +			if ((state->aud_input == CX25840_AUDIO6) ||
> +			    (state->aud_input == CX25840_AUDIO7)) {
> +				cx25840_write(client, 0x124, 0x00);
> +			} else {
> +				/* Audio channel 1 src : Parallel 1 */
> +				cx25840_write(client, 0x124, 0x03);
> +			}
> +
> +			/* Select AFE clock pad output source */
> +			if (is_cx2388x(state))
> +				cx25840_write(client, 0x144, 0x05);
> +
> +			/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
> +			cx25840_write(client, 0x914, 0xa0);
> +
> +			/* I2S_OUT_CTL:
> +			 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
> +			 * I2S_OUT_MASTER_MODE = Master
> +			 */
> +			cx25840_write(client, 0x918, 0xa0);
> +			cx25840_write(client, 0x919, 0x01);
> +
> +			if ((state->aud_input == CX25840_AUDIO6) ||
> +			    (state->aud_input == CX25840_AUDIO7)) {
> +				cx25840_write4(client, 0x910, 0);
> +				cx25840_write4(client, 0x8d0, 0x00063073);
> +				/* Reset path1 volume control */
> +				cx25840_write4(client, 0x8d4, 0x7fff0024);
> +			} else { /* default for all sources, not only AUDIO8 */
> +				cx25840_write4(client, 0x910, 0x12b000c9);
> +				cx25840_write4(client, 0x8d0, 0x1f063870);
> +			}
> +		} else if (state->aud_input == CX25840_AUDIO_SERIAL) {
>  			/* Set Path1 to Serial Audio Input */
>  			cx25840_write4(client, 0x8d0, 0x01011012);
> -
> -			/* The microcontroller should not be started for the
> -			 * non-tuner inputs: autodetection is specific for
> -			 * TV audio. */
>  		} else {
>  			/* Set Path1 to Analog Demod Main Channel */
>  			cx25840_write4(client, 0x8d0, 0x1f063870);
> @@ -463,7 +494,12 @@ void cx25840_audio_set_path(struct i2c_c
>  	set_audclk_freq(client, state->audclk_freq);
>  
>  	if (!is_cx2583x(state)) {
> -		if (state->aud_input != CX25840_AUDIO_SERIAL) {
> +		/* The microcontroller should not be started for the
> +		 * non-tuner inputs: autodetection is specific for
> +		 * TV audio. */
> +		if ((state->aud_input != CX25840_AUDIO_SERIAL) &&
> +		    (state->aud_input != CX25840_AUDIO6) &&
> +		    (state->aud_input != CX25840_AUDIO7)) {
>  			/* When the microcontroller detects the
>  			 * audio format, it will unmute the lines */
>  			cx25840_and_or(client, 0x803, ~0x10, 0x10);
> @@ -471,10 +507,6 @@ void cx25840_audio_set_path(struct i2c_c
>  
>  		/* deassert soft reset */
>  		cx25840_and_or(client, 0x810, ~0x1, 0x00);
> -
> -		/* Ensure the controller is running when we exit */
> -		if (is_cx2388x(state) || is_cx231xx(state))
> -			cx25840_and_or(client, 0x803, ~0x10, 0x10);
>  	}
>  }
>  
> diff -Naurp a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
> --- a/drivers/media/video/cx25840/cx25840-core.c	2012-01-14 18:02:41.968366747 +0100
> +++ b/drivers/media/video/cx25840/cx25840-core.c	2012-01-14 18:03:33.024366746 +0100
> @@ -73,11 +73,18 @@ MODULE_LICENSE("GPL");
>  #define CX25840_IR_IRQEN_REG	0x214
>  
>  static int cx25840_debug;
> -
> -module_param_named(debug,cx25840_debug, int, 0644);
> -
> +module_param_named(debug, cx25840_debug, int, 0644);
>  MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
>  
> +static unsigned int radio_deemphasis = 0;
> +module_param(radio_deemphasis, int, 0644);
> +MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant "
> +				   "[0=75us (USA) 1=50us (elsewhere)]");
> +
> +static unsigned int audio_standard_force = 0;
> +module_param(audio_standard_force, int, 0644);
> +MODULE_PARM_DESC(audio_standard_force, "Force audio standard for tuners with broken"
> +				       "microcontroler autodetection [0=Off (default) 1=TV 2=TV+FM]");
>  
>  /* ----------------------------------------------------------------------- */
>  
> @@ -474,7 +481,7 @@ static void cx23885_initialize(struct i2
>  	cx25840_and_or(client, 0x102, ~0x01, 0x01);
>  	cx25840_and_or(client, 0x102, ~0x01, 0x00);
>  
> -	/* Stop microcontroller */
> +	/* 2. Stop microcontroller */
>  	cx25840_and_or(client, 0x803, ~0x10, 0x00);
>  
>  	/* DIF in reset? */
> @@ -536,12 +543,6 @@ static void cx23885_initialize(struct i2
>  	cx25840_write4(client, 0x10c, 0x002be2c9);
>  	cx25840_write4(client, 0x108, 0x0000040f);
>  
> -	/* Luma */
> -	cx25840_write4(client, 0x414, 0x00107d12);
> -
> -	/* Chroma */
> -	cx25840_write4(client, 0x420, 0x3d008282);
> -
>  	/*
>  	 * Aux PLL
>  	 * Initial setup for audio sample clock:
> @@ -586,12 +587,6 @@ static void cx23885_initialize(struct i2
>  	/* VIN1 & VIN5 */
>  	cx25840_write(client, 0x103, 0x11);
>  
> -	/* Enable format auto detect */
> -	cx25840_write(client, 0x400, 0);
> -	/* Fast subchroma lock */
> -	/* White crush, Chroma AGC & Chroma Killer enabled */
> -	cx25840_write(client, 0x401, 0xe8);
> -
>  	/* Select AFE clock pad output source */
>  	cx25840_write(client, 0x144, 0x05);
>  
> @@ -604,7 +599,14 @@ static void cx23885_initialize(struct i2
>  	cx25840_write(client, 0x160, 0x1d);
>  	cx25840_write(client, 0x164, 0x00);
>  
> -	/* Do the firmware load in a work handler to prevent.
> +	/* Enable format auto detect */
> +	cx25840_write(client, 0x400, 0);
> +
> +	/* 4. Reset tuner autodetection */
> +	cx25840_and_or(client, 0x13c, ~0x01, 0x01);
> +	cx25840_and_or(client, 0x13c, ~0x01, 0x00);
> +
> +	/* 5. Do the firmware load in a work handler to prevent.
>  	   Otherwise the kernel is blocked waiting for the
>  	   bit-banging i2c interface to finish uploading the
>  	   firmware. */
> @@ -617,13 +619,32 @@ static void cx23885_initialize(struct i2
>  	finish_wait(&state->fw_wait, &wait);
>  	destroy_workqueue(q);
>  
> +	/* 7. Reset and initialize video decoder */
> +	cx25840_write4(client, 0x4a4, 0x8000);
> +	cx25840_write4(client, 0x4a4, 0);
> +	cx25840_write(client, 0x402, 0x00);
> +
> +	/* 8. White crush, Chroma AGC & Chroma Killer enabled.
> +	 * From datasheet and spoted from Leadtek drivers we
> +	 * should not set Fast Lock and Auto Chroma Lock Speed.
> +	 */
> +	cx25840_write(client, 0x401, 0xe0);
> +
> +	/* Luma */
> +	cx25840_write4(client, 0x414, 0x00107d12);
> +
> +	/* Chroma */
> +	cx25840_write4(client, 0x420, 0x3d008282);
> +
>  	cx25840_std_setup(client);
>  
>  	/* (re)set input */
>  	set_input(client, state->vid_input, state->aud_input);
>  
> -	/* start microcontroller */
> -	cx25840_and_or(client, 0x803, ~0x10, 0x10);
> +	/* start microcontroller only for tuner inputs */
> +	if ((state->aud_input != CX25840_AUDIO6) &&
> +	    (state->aud_input != CX25840_AUDIO7))
> +		cx25840_and_or(client, 0x803, ~0x10, 0x10);
>  
>  	/* Disable and clear video interrupts - we don't use them */
>  	cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
> @@ -678,6 +699,7 @@ static void cx231xx_initialize(struct i2
>  
>  	/* Enable format auto detect */
>  	cx25840_write(client, 0x400, 0);
> +
>  	/* Fast subchroma lock */
>  	/* White crush, Chroma AGC & Chroma Killer enabled */
>  	cx25840_write(client, 0x401, 0xe8);
> @@ -866,72 +888,112 @@ static void input_change(struct i2c_clie
>  {
>  	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
>  	v4l2_std_id std = state->std;
> +	u8 fmt = cx25840_read(client, 0x40D);
> +	int hw_fix = (audio_standard_force > state->pvr150_workaround) ?
> +			audio_standard_force : state->pvr150_workaround;
>  
>  	/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
>  	if (std & V4L2_STD_SECAM) {
>  		cx25840_write(client, 0x402, 0);
> -	}
> -	else {
> +	} else {
>  		cx25840_write(client, 0x402, 0x04);
>  		cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
>  	}
> -	cx25840_and_or(client, 0x401, ~0x60, 0);
> -	cx25840_and_or(client, 0x401, ~0x60, 0x60);
> +
> +	/* Step 9. Improve format detection */
> +	if (((fmt & 0x0f) > 0x3) ||
> +	    ((fmt & 0x0f) < 0x9)) {
> +		/* Switch to NTSC and back */
> +		u8 val = cx25840_read(client, 0x400);
> +		cx25840_and_or(client, 0x400, ~0x0f, 0x01);
> +		/* Disable LCOMB_3LN_EN and LCOMB_2LN_EN */
> +		cx25840_and_or(client, 0x47b, ~0x06, 0);
> +		cx25840_and_or(client, 0x400, ~0x0f, (val & 0x0f));
> +
> +		/* Toggle CAGCEN and CKILLEN */
> +		cx25840_and_or(client, 0x401, ~0x60, 0);
> +		cx25840_and_or(client, 0x401, ~0x60, 0x60);
> +	} else if ((fmt & 0x0f) == 0x9) {
> +		/* Toggle CKILLEN */
> +		cx25840_and_or(client, 0x401, ~0x20, 0);
> +		cx25840_and_or(client, 0x401, ~0x20, 0x20);
> +		/* Standard autodetection */
> +		cx25840_and_or(client, 0x400, ~0x0f, 0x00);
> +	} else {
> +		/* Toggle CAGCEN and CKILLEN */
> +		cx25840_and_or(client, 0x401, ~0x60, 0);
> +		cx25840_and_or(client, 0x401, ~0x60, 0x60);
> +	}
>  
>  	/* Don't write into audio registers on cx2583x chips */
>  	if (is_cx2583x(state))
>  		return;
>  
> +	/* Toggle microcontroller only when running */
> +	if (cx25840_read(client, 0x803) & 0x10) {
> +		cx25840_and_or(client, 0x803, ~0x10, 0x00);
> +		msleep(1);
> +		cx25840_and_or(client, 0x803, ~0x10, 0x10);
> +	}
> +
>  	cx25840_and_or(client, 0x810, ~0x01, 1);
>  
> +	/* Use default audio format control */
> +	cx25840_write(client, 0x80b, 0);
> +
>  	if (state->radio) {
> -		cx25840_write(client, 0x808, 0xf9);
> -		cx25840_write(client, 0x80b, 0x00);
> -	}
> -	else if (std & V4L2_STD_525_60) {
> -		/* Certain Hauppauge PVR150 models have a hardware bug
> -		   that causes audio to drop out. For these models the
> -		   audio standard must be set explicitly.
> -		   To be precise: it affects cards with tuner models
> -		   85, 99 and 112 (model numbers from tveeprom). */
> -		int hw_fix = state->pvr150_workaround;
> -
> -		if (std == V4L2_STD_NTSC_M_JP) {
> -			/* Japan uses EIAJ audio standard */
> -			cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7);
> -		} else if (std == V4L2_STD_NTSC_M_KR) {
> -			/* South Korea uses A2 audio standard */
> -			cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8);
> -		} else {
> -			/* Others use the BTSC audio standard */
> -			cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
> -		}
> -		cx25840_write(client, 0x80b, 0x00);
> -	} else if (std & V4L2_STD_PAL) {
> -		/* Autodetect audio standard and audio system */
> +		/* Disable fm_deviation, set deemphasis, don't mute and prefer stereo */
> +		cx25840_write(client, 0x809, radio_deemphasis ? 0x24 : 0x04);
> +		/* For FM mode hw_fix is not necessary */
> +		cx25840_write(client, 0x808, (hw_fix > 1) ? 0xef : 0xf9);
> +	} else if (std == V4L2_STD_NTSC_M_JP) {
> +		/* Japan uses EIAJ audio standard */
> +		cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7);
> +	} else if (std == V4L2_STD_NTSC_M_KR) {
> +		/* South Korea uses A2 audio standard */
> +		cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8);
> +	} else if (std & (V4L2_STD_525_60 | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
> +		/* NTSC, PAL-60, PAL-M and PAL-N uses BTSC audio standard */
> +		cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
> +	} else if ((std & (V4L2_STD_PAL_BG | V4L2_STD_PAL_H)) &&
> +		   !(std & V4L2_STD_PAL_DK) &&
> +		   !(std & V4L2_STD_PAL_I)) {
> +		/* A2-BG */
> +		cx25840_write(client, 0x808, hw_fix ? 0x4f : 0xf0);
> +	} else if (!(std & (V4L2_STD_PAL_BG | V4L2_STD_PAL_H)) &&
> +		    (std & V4L2_STD_PAL_DK) &&
> +		   !(std & V4L2_STD_PAL_I)) {
> +		/* A2-DK1 */
> +		cx25840_write(client, 0x808, hw_fix ? 0x5f : 0xf1);
> +	} else if (!(std & (V4L2_STD_PAL_BG | V4L2_STD_PAL_H)) &&
> +		   !(std & V4L2_STD_PAL_DK) &&
> +		    (std & V4L2_STD_PAL_I)) {
> +		/* A1 */
> +		cx25840_write(client, 0x808, hw_fix ? 0x8f : 0xf4);
> +	} else if ((std & (V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)) &&
> +		   !(std & V4L2_STD_SECAM_DK) &&
> +		   !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
> +		/* NICAM-BG */
> +		cx25840_write(client, 0x808, hw_fix ? 0xaf : 0xf0);
> +	} else if (!(std & (V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)) &&
> +		    (std & V4L2_STD_SECAM_DK) &&
> +		   !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
> +		/* NICAM-DK */
> +		cx25840_write(client, 0x808, hw_fix ? 0xbf : 0xf1);
> +	} else if (!(std & (V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)) &&
> +		   !(std & V4L2_STD_SECAM_DK) &&
> +		    (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
> +		/* 6.5 MHz carrier to be interpreted as System L */
> +		cx25840_write(client, 0x80b, 0x08);
> +		/* NICAM-L */
> +		cx25840_write(client, 0x808, hw_fix ? 0xdf : 0xf5);
> +        } else if (std & V4L2_STD_SECAM) {
> +		/* 6.5 MHz carrier to be autodetected */
> +		cx25840_write(client, 0x80b, 0x10);
>  		cx25840_write(client, 0x808, 0xff);
> -		/* Since system PAL-L is pretty much non-existent and
> -		   not used by any public broadcast network, force
> -		   6.5 MHz carrier to be interpreted as System DK,
> -		   this avoids DK audio detection instability */
> -	       cx25840_write(client, 0x80b, 0x00);
> -	} else if (std & V4L2_STD_SECAM) {
> -		/* Autodetect audio standard and audio system */
> +	} else {
> +		/* Audio standard autodetection - not working on some cards */
>  		cx25840_write(client, 0x808, 0xff);
> -		/* If only one of SECAM-DK / SECAM-L is required, then force
> -		  6.5MHz carrier, else autodetect it */
> -		if ((std & V4L2_STD_SECAM_DK) &&
> -		    !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
> -			/* 6.5 MHz carrier to be interpreted as System DK */
> -			cx25840_write(client, 0x80b, 0x00);
> -	       } else if (!(std & V4L2_STD_SECAM_DK) &&
> -			  (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
> -			/* 6.5 MHz carrier to be interpreted as System L */
> -			cx25840_write(client, 0x80b, 0x08);
> -	       } else {
> -			/* 6.5 MHz carrier to be autodetected */
> -			cx25840_write(client, 0x80b, 0x10);
> -	       }
>  	}
>  
>  	cx25840_and_or(client, 0x810, ~0x01, 0);
> @@ -950,7 +1012,7 @@ static int set_input(struct i2c_client *
>  	u8 reg;
>  
>  	v4l_dbg(1, cx25840_debug, client,
> -		"decoder set video input %d, audio input %d\n",
> +		"decoder set video input 0x%x, audio input 0x%x\n",
>  		vid_input, aud_input);
>  
>  	if (vid_input >= CX25840_VIN1_CH1) {
> @@ -1043,49 +1105,6 @@ static int set_input(struct i2c_client *
>  	cx25840_audio_set_path(client);
>  	input_change(client);
>  
> -	if (is_cx2388x(state)) {
> -		/* Audio channel 1 src : Parallel 1 */
> -		cx25840_write(client, 0x124, 0x03);
> -
> -		/* Select AFE clock pad output source */
> -		cx25840_write(client, 0x144, 0x05);
> -
> -		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
> -		cx25840_write(client, 0x914, 0xa0);
> -
> -		/* I2S_OUT_CTL:
> -		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
> -		 * I2S_OUT_MASTER_MODE = Master
> -		 */
> -		cx25840_write(client, 0x918, 0xa0);
> -		cx25840_write(client, 0x919, 0x01);
> -	} else if (is_cx231xx(state)) {
> -		/* Audio channel 1 src : Parallel 1 */
> -		cx25840_write(client, 0x124, 0x03);
> -
> -		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
> -		cx25840_write(client, 0x914, 0xa0);
> -
> -		/* I2S_OUT_CTL:
> -		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
> -		 * I2S_OUT_MASTER_MODE = Master
> -		 */
> -		cx25840_write(client, 0x918, 0xa0);
> -		cx25840_write(client, 0x919, 0x01);
> -	}
> -
> -	if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) ||
> -		(aud_input == CX25840_AUDIO6))) {
> -		/* Configure audio from LR1 or LR2 input */
> -		cx25840_write4(client, 0x910, 0);
> -		cx25840_write4(client, 0x8d0, 0x63073);
> -	} else
> -	if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
> -		/* Configure audio from tuner/sif input */
> -		cx25840_write4(client, 0x910, 0x12b000c9);
> -		cx25840_write4(client, 0x8d0, 0x1f063870);
> -	}
> -
>  	return 0;
>  }
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux