1
0
Fork 0

Sound: WM8994: Support I2S0 channel

This patch modifies the WM8994 codec to support I2S0 channel
in codec slave mode

Signed-off-by: Dani Krishna Mohan <krishna.md@samsung.com>
utp
Dani Krishna Mohan 2013-09-11 16:38:46 +05:30 committed by Tom Rini
parent d7884e047d
commit d981d80d74
4 changed files with 159 additions and 53 deletions

View File

@ -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)),

View File

@ -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__);
@ -607,6 +612,38 @@ static int wm8994_init_volume_aif2_dac1(void)
return 0;
}
/*
* 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
*
@ -614,7 +651,8 @@ static int wm8994_init_volume_aif2_dac1(void)
*
* @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_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING,
WM8994_AIF2DACR_TO_DAC1R_MASK,
WM8994_AIF2DACR_TO_DAC1R);
ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING,
WM8994_AIF1DAC1R_TO_DAC1R);
/* 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);
/* GPIO Settings for AIF1 */
ret |= wm8994_i2c_write(WM8994_GPIO_1, WM8994_GPIO_DIR_OUTPUT
| WM8994_GPIO_FUNCTION_I2S_CLK
| WM8994_GPIO_INPUT_DEBOUNCE);
/* 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);
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);
/* 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);
ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING,
WM8994_AIF2DACR_TO_DAC1R_MASK,
WM8994_AIF2DACR_TO_DAC1R);
/* 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);
/* 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;

View File

@ -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

View File

@ -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 */
};
/*