diff options
| -rw-r--r-- | drivers/sound/sound.c | 17 | ||||
| -rw-r--r-- | drivers/sound/wm8994.c | 155 | ||||
| -rw-r--r-- | drivers/sound/wm8994_registers.h | 39 | ||||
| -rw-r--r-- | include/i2s.h | 1 | 
4 files changed, 159 insertions, 53 deletions
| diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index 6fcc75da5..f3342f23f 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -36,8 +36,7 @@ static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)  	int error = 0;  	int base; -	node = fdtdec_next_compatible(blob, 0, -					COMPAT_SAMSUNG_EXYNOS5_SOUND); +	node = fdt_path_offset(blob, "i2s");  	if (node <= 0) {  		debug("EXYNOS_SOUND: No node for sound in device tree\n");  		return -1; @@ -80,6 +79,11 @@ static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)  				node, "samsung,i2s-bit-clk-framesize", -1);  	error |= i2s->bfs;  	debug("bfs = %d\n", i2s->bfs); + +	i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1); +	error |= i2s->id; +	debug("id = %d\n", i2s->id); +  	if (error == -1) {  		debug("fail to get sound i2s node properties\n");  		return -1; @@ -92,6 +96,7 @@ static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)  	i2s->channels = I2S_CHANNELS;  	i2s->rfs = I2S_RFS;  	i2s->bfs = I2S_BFS; +	i2s->id = 0;  #endif  	return 0;  } @@ -130,10 +135,10 @@ static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)  #endif  	if (!strcmp(codectype, "wm8994")) {  		/* Check the codec type and initialise the same */ -		ret = wm8994_init(blob, WM8994_AIF2, -			pi2s_tx->samplingrate, -			(pi2s_tx->samplingrate * (pi2s_tx->rfs)), -			pi2s_tx->bitspersample, pi2s_tx->channels); +		ret = wm8994_init(blob, pi2s_tx->id + 1, +				pi2s_tx->samplingrate, +				(pi2s_tx->samplingrate * (pi2s_tx->rfs)), +				pi2s_tx->bitspersample, pi2s_tx->channels);  	} else if (!strcmp(codectype, "max98095")) {  		ret = max98095_init(blob, pi2s_tx->samplingrate,  				(pi2s_tx->samplingrate * (pi2s_tx->rfs)), diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c index 37e354c5c..f8e9a6ead 100644 --- a/drivers/sound/wm8994.c +++ b/drivers/sound/wm8994.c @@ -432,12 +432,12 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)  	int ret;  	/* AIF(1/0) register adress offset calculated */ -	if (aif) +	if (aif-1)  		offset = 4;  	else  		offset = 0; -	switch (wm8994->sysclk[aif]) { +	switch (wm8994->sysclk[aif-1]) {  	case WM8994_SYSCLK_MCLK1:  		reg1 |= SEL_MCLK1;  		rate = wm8994->mclk[0]; @@ -460,7 +460,7 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)  	default:  		debug("%s: Invalid input clock selection [%d]\n", -		      __func__, wm8994->sysclk[aif]); +		      __func__, wm8994->sysclk[aif-1]);  		return -1;  	} @@ -470,13 +470,18 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)  		reg1 |= WM8994_AIF1CLK_DIV;  	} -	wm8994->aifclk[aif] = rate; +	wm8994->aifclk[aif-1] = rate;  	ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset,  				WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,  				reg1); -	ret |= wm8994_update_bits(WM8994_CLOCKING_1, +	if (aif == WM8994_AIF1) +		ret |= wm8994_update_bits(WM8994_CLOCKING_1, +			WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK, +			WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); +	else if (aif == WM8994_AIF2) +		ret |= wm8994_update_bits(WM8994_CLOCKING_1,  			WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |  			WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |  			WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); @@ -536,7 +541,7 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,  					break;  			if (i == ARRAY_SIZE(opclk_divs)) {  				debug("%s frequency divisor not found\n", -					__func__); +				      __func__);  				return -1;  			}  			ret = wm8994_update_bits(WM8994_CLOCKING_2, @@ -554,7 +559,7 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,  		return -1;  	} -	ret |= configure_aif_clock(wm8994, aif_id - 1); +	ret |= configure_aif_clock(wm8994, aif_id);  	if (ret < 0) {  		debug("%s: codec register access error\n", __func__); @@ -608,13 +613,46 @@ static int wm8994_init_volume_aif2_dac1(void)  }  /* + * Initializes Volume for AIF1 to HP path + * + * @returns -1 for error  and 0 Success. + * + */ +static int wm8994_init_volume_aif1_dac1(void) +{ +	int ret = 0; + +	/* Unmute AIF1DAC */ +	ret |= wm8994_i2c_write(WM8994_AIF1_DAC_FILTERS_1, 0x0000); + +	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME, +			WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK | +			WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0); + +	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME, +			WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK | +			WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0); +	/* Head Phone Volume */ +	ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D); +	ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D); + +	if (ret < 0) { +		debug("%s: codec register access error\n", __func__); +		return -1; +	} + +	return 0; +} + +/*   * Intialise wm8994 codec device   *   * @param wm8994	wm8994 information   *   * @returns -1 for error  and 0 Success.   */ -static int wm8994_device_init(struct wm8994_priv *wm8994) +static int wm8994_device_init(struct wm8994_priv *wm8994, +			      enum en_audio_interface aif_id)  {  	const char *devname;  	unsigned short reg_data; @@ -661,13 +699,30 @@ static int wm8994_device_init(struct wm8994_priv *wm8994)  	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,  				WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA); -	/* Power enable for AIF2 and DAC1 */ -	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5, -		WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | -		WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK, -		WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | WM8994_DAC1L_ENA | -		WM8994_DAC1R_ENA); +	if (aif_id == WM8994_AIF1) { +		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_2, +					WM8994_TSHUT_ENA | WM8994_MIXINL_ENA | +					WM8994_MIXINR_ENA | WM8994_IN2L_ENA | +					WM8994_IN2R_ENA); + +		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_4, +					WM8994_ADCL_ENA | WM8994_ADCR_ENA | +					WM8994_AIF1ADC1R_ENA | +					WM8994_AIF1ADC1L_ENA); +		/* Power enable for AIF1 and DAC1 */ +		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_5, +					WM8994_AIF1DACL_ENA | +					WM8994_AIF1DACR_ENA | +					WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); +	} else if (aif_id == WM8994_AIF2) { +		/* Power enable for AIF2 and DAC1 */ +		ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5, +			WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | +			WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK, +			WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | +			WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); +	}  	/* Head Phone Initialisation */  	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,  		WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK, @@ -695,35 +750,49 @@ static int wm8994_device_init(struct wm8994_priv *wm8994)  	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_2,  			WM8994_DAC1R_TO_HPOUT1R_MASK, WM8994_DAC1R_TO_HPOUT1R); -	/* Routing AIF2 to DAC1 */ -	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING, -			WM8994_AIF2DACL_TO_DAC1L_MASK, -			WM8994_AIF2DACL_TO_DAC1L); +	if (aif_id == WM8994_AIF1) { +		/* Routing AIF1 to DAC1 */ +		ret |= wm8994_i2c_write(WM8994_DAC1_LEFT_MIXER_ROUTING, +				WM8994_AIF1DAC1L_TO_DAC1L); + +		ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING, +					WM8994_AIF1DAC1R_TO_DAC1R); + +		/* GPIO Settings for AIF1 */ +		ret |=  wm8994_i2c_write(WM8994_GPIO_1, WM8994_GPIO_DIR_OUTPUT +					 | WM8994_GPIO_FUNCTION_I2S_CLK +					 | WM8994_GPIO_INPUT_DEBOUNCE); -	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING, -			WM8994_AIF2DACR_TO_DAC1R_MASK, -			WM8994_AIF2DACR_TO_DAC1R); +		ret |= wm8994_init_volume_aif1_dac1(); +	} else if (aif_id == WM8994_AIF2) { +		/* Routing AIF2 to DAC1 */ +		ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING, +				WM8994_AIF2DACL_TO_DAC1L_MASK, +				WM8994_AIF2DACL_TO_DAC1L); -	 /* GPIO Settings for AIF2 */ -	 /* B CLK */ -	ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK | -				WM8994_GPIO_FUNCTION_MASK , -				WM8994_GPIO_DIR_OUTPUT | -				WM8994_GPIO_FUNCTION_I2S_CLK); +		ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING, +				WM8994_AIF2DACR_TO_DAC1R_MASK, +				WM8994_AIF2DACR_TO_DAC1R); -	/* LR CLK */ -	ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK | -				WM8994_GPIO_FUNCTION_MASK, -				WM8994_GPIO_DIR_OUTPUT | -				WM8994_GPIO_FUNCTION_I2S_CLK); +		/* GPIO Settings for AIF2 */ +		/* B CLK */ +		ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK | +					WM8994_GPIO_FUNCTION_MASK , +					WM8994_GPIO_DIR_OUTPUT); -	/* DATA */ -	ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK | -				WM8994_GPIO_FUNCTION_MASK, -				WM8994_GPIO_DIR_OUTPUT | -				WM8994_GPIO_FUNCTION_I2S_CLK); +		/* LR CLK */ +		ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK | +					WM8994_GPIO_FUNCTION_MASK, +					WM8994_GPIO_DIR_OUTPUT); + +		/* DATA */ +		ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK | +					WM8994_GPIO_FUNCTION_MASK, +					WM8994_GPIO_DIR_OUTPUT); + +		ret |= wm8994_init_volume_aif2_dac1(); +	} -	ret |= wm8994_init_volume_aif2_dac1();  	if (ret < 0)  		goto err; @@ -795,7 +864,7 @@ static int get_codec_values(struct sound_codec_info *pcodec_info,  	return 0;  } -/*wm8994 Device Initialisation */ +/* WM8994 Device Initialisation */  int wm8994_init(const void *blob, enum en_audio_interface aif_id,  			int sampling_rate, int mclk_freq,  			int bits_per_sample, unsigned int channels) @@ -813,15 +882,15 @@ int wm8994_init(const void *blob, enum en_audio_interface aif_id,  	g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr;  	wm8994_i2c_init(pcodec_info->i2c_bus); -	if (pcodec_info->codec_type == CODEC_WM_8994) +	if (pcodec_info->codec_type == CODEC_WM_8994) {  		g_wm8994_info.type = WM8994; -	else { +	} else {  		debug("%s: Codec id [%d] not defined\n", __func__, -				pcodec_info->codec_type); +		      pcodec_info->codec_type);  		return -1;  	} -	ret = wm8994_device_init(&g_wm8994_info); +	ret = wm8994_device_init(&g_wm8994_info, aif_id);  	if (ret < 0) {  		debug("%s: wm8994 codec chip init failed\n", __func__);  		return ret; diff --git a/drivers/sound/wm8994_registers.h b/drivers/sound/wm8994_registers.h index 1e987c2fd..0aba2fdfd 100644 --- a/drivers/sound/wm8994_registers.h +++ b/drivers/sound/wm8994_registers.h @@ -13,6 +13,7 @@  #define WM8994_SOFTWARE_RESET                   0x00  #define WM8994_POWER_MANAGEMENT_1               0x01  #define WM8994_POWER_MANAGEMENT_2               0x02 +#define WM8994_POWER_MANAGEMENT_4		0x04  #define WM8994_POWER_MANAGEMENT_5               0x05  #define WM8994_LEFT_OUTPUT_VOLUME               0x1C  #define WM8994_RIGHT_OUTPUT_VOLUME              0x1D @@ -38,6 +39,7 @@  #define WM8994_AIF2_CONTROL_2                   0x311  #define WM8994_AIF2_MASTER_SLAVE                0x312  #define WM8994_AIF2_BCLK                        0x313 +#define WM8994_AIF1_DAC_FILTERS_1		0x420  #define WM8994_AIF2_DAC_LEFT_VOLUME             0x502  #define WM8994_AIF2_DAC_RIGHT_VOLUME            0x503  #define WM8994_AIF2_DAC_FILTERS_1               0x520 @@ -45,6 +47,7 @@  #define WM8994_DAC1_RIGHT_MIXER_ROUTING         0x602  #define WM8994_DAC1_LEFT_VOLUME                 0x610  #define WM8994_DAC1_RIGHT_VOLUME                0x611 +#define WM8994_GPIO_1				0x700  #define WM8994_GPIO_3                           0x702  #define WM8994_GPIO_4                           0x703  #define WM8994_GPIO_5                           0x704 @@ -82,6 +85,20 @@  /* OPCLK_ENA */  #define WM8994_OPCLK_ENA                        0x0800 +#define WM8994_TSHUT_ENA			0x4000 +#define WM8994_MIXINL_ENA			0x0200 +#define WM8994_MIXINR_ENA			0x0100 +#define WM8994_IN2L_ENA				0x0080 +#define WM8994_IN2R_ENA				0x0020 + +/* + * R5 (0x04) - Power Management (4) + */ +#define WM8994_ADCL_ENA				0x0001 +#define WM8994_ADCR_ENA				0x0002 +#define WM8994_AIF1ADC1R_ENA			0x0100 +#define WM8994_AIF1ADC1L_ENA			0x0200 +  /*   * R5 (0x05) - Power Management (5)   */ @@ -91,6 +108,12 @@  /* AIF2DACR_ENA */  #define WM8994_AIF2DACR_ENA                     0x1000  #define WM8994_AIF2DACR_ENA_MASK                0x1000 +/* AIF1DACL_ENA */ +#define WM8994_AIF1DACL_ENA			0x0200 +#define WM8994_AIF1DACL_ENA_MASK		0x0200 +/* AIF1DACR_ENA */ +#define WM8994_AIF1DACR_ENA			0x0100 +#define WM8994_AIF1DACR_ENA_MASK		0x0100  /* DAC1L_ENA */  #define WM8994_DAC1L_ENA                        0x0002  #define WM8994_DAC1L_ENA_MASK                   0x0002 @@ -170,6 +193,9 @@  /*   * R520 (0x208) - Clocking (1)   */ +/* AIF1DSPCLK_ENA */ +#define WM8994_AIF1DSPCLK_ENA			0x0008 +#define WM8994_AIF1DSPCLK_ENA_MASK		0x0008  /* AIF2DSPCLK_ENA */  #define WM8994_AIF2DSPCLK_ENA                   0x0004  #define WM8994_AIF2DSPCLK_ENA_MASK              0x0004 @@ -254,6 +280,8 @@  /* AIF2DACL_TO_DAC1L */  #define WM8994_AIF2DACL_TO_DAC1L                0x0004  #define WM8994_AIF2DACL_TO_DAC1L_MASK           0x0004 +/* AIF1DAC1L_TO_DAC1L */ +#define WM8994_AIF1DAC1L_TO_DAC1L		0x0001  /*   * R1538 (0x602) - DAC1 Right Mixer Routing @@ -261,6 +289,8 @@  /* AIF2DACR_TO_DAC1R */  #define WM8994_AIF2DACR_TO_DAC1R                0x0004  #define WM8994_AIF2DACR_TO_DAC1R_MASK           0x0004 +/* AIF1DAC1R_TO_DAC1R */ +#define WM8994_AIF1DAC1R_TO_DAC1R		0x0001  /*   * R1552 (0x610) - DAC1 Left Volume @@ -285,11 +315,12 @@   *  GPIO   */  /* OUTPUT PIN */ -#define WM8994_GPIO_DIR_OUTPUT                   0x8000 +#define WM8994_GPIO_DIR_OUTPUT			0x8000  /* GPIO PIN MASK */ -#define WM8994_GPIO_DIR_MASK                     0xFFE0 +#define WM8994_GPIO_DIR_MASK			0xFFE0  /* I2S CLK */ -#define WM8994_GPIO_FUNCTION_I2S_CLK             0x0000 +#define WM8994_GPIO_FUNCTION_I2S_CLK		0x0001 +#define WM8994_GPIO_INPUT_DEBOUNCE		0x0100  /* GPn FN */ -#define WM8994_GPIO_FUNCTION_MASK                0x001F +#define WM8994_GPIO_FUNCTION_MASK		0x001F  #endif diff --git a/include/i2s.h b/include/i2s.h index aee52e7f1..8dd2cc388 100644 --- a/include/i2s.h +++ b/include/i2s.h @@ -85,6 +85,7 @@ struct i2stx_info {  	unsigned int bitspersample;	/* bits per sample */  	unsigned int channels;		/* audio channels */  	unsigned int base_address;	/* I2S Register Base */ +	unsigned int id;		/* I2S controller id */  };  /* |