[U-Boot] [PATCH V2 0/5] EXYNOS: I2S: Enable I2S0 channel

This patch set adds I2S-0 support and retains I2S-1 support. The default i2s channel can be selected through DT.
Changes in V2: - Enabled I2S-0 support through DT - Retained I2S-1 support
Changes in V1: - Added I2S-0 support - Removed I2S-1 support
Dani Krishna Mohan (5): Sound: WM8994: Support I2S0 channel DTS: Addition of I2S0 channel and replacing I2S1 ARM: Added I2S0 clocks for audio Sound: I2S: Replacing I2S1 with I2S0 channel. Sound: MAX98095: Support I2S0 channel
arch/arm/cpu/armv7/exynos/clock.c | 57 ++++++--- arch/arm/cpu/armv7/exynos/pinmux.c | 15 ++- arch/arm/dts/exynos5250.dtsi | 19 +++ arch/arm/include/asm/arch-exynos/clk.h | 5 +- arch/arm/include/asm/arch-exynos/clock.h | 4 + arch/arm/include/asm/arch-exynos/cpu.h | 4 + arch/arm/include/asm/arch-exynos/i2s-regs.h | 6 + arch/arm/include/asm/arch-exynos/periph.h | 1 + board/samsung/dts/exynos5250-smdk5250.dts | 13 +-- board/samsung/dts/exynos5250-snow.dts | 14 +-- drivers/sound/max98095.c | 128 ++++++++++++-------- drivers/sound/max98095.h | 10 +- drivers/sound/samsung-i2s.c | 52 ++++++--- drivers/sound/sound.c | 28 +++-- drivers/sound/wm8994.c | 167 +++++++++++++++++++-------- drivers/sound/wm8994_registers.h | 39 ++++++- include/i2s.h | 1 + 17 files changed, 403 insertions(+), 160 deletions(-)

This patch modifies the WM8994 codec to support I2S0 channel in codec slave mode
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com --- drivers/sound/sound.c | 17 ++-- drivers/sound/wm8994.c | 167 +++++++++++++++++++++++++++----------- drivers/sound/wm8994_registers.h | 39 ++++++++- include/i2s.h | 1 + 4 files changed, 165 insertions(+), 59 deletions(-)
diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index 6fcc75d..f3342f2 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 37e354c..f8e9a6e 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); - - 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 | - 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 | - WM8994_GPIO_FUNCTION_I2S_CLK); - - /* 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_init_volume_aif2_dac1(); + 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_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); + + 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(); + } + 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 1e987c2..0aba2fd 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 aee52e7..8dd2cc3 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 */ };
/*

This patch enables default I2S0 channel.And I2S platform parameter has been moved to a common file viz exynos5.dtsi.
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com --- arch/arm/dts/exynos5250.dtsi | 19 +++++++++++++++++++ board/samsung/dts/exynos5250-smdk5250.dts | 13 ++++++------- board/samsung/dts/exynos5250-snow.dts | 14 +++++++------- 3 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index 4fff5e3..1c5474f 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -93,9 +93,28 @@ interrupts = <0 63 0>; };
+ sound@3830000 { + compatible = "samsung,exynos-sound"; + reg = <0x3830000 0x50>; + samsung,i2s-epll-clock-frequency = <192000000>; + samsung,i2s-sampling-rate = <48000>; + samsung,i2s-bits-per-sample = <16>; + samsung,i2s-channels = <2>; + samsung,i2s-lr-clk-framesize = <256>; + samsung,i2s-bit-clk-framesize = <32>; + samsung,i2s-id = <0>; + }; + sound@12d60000 { compatible = "samsung,exynos-sound"; reg = <0x12d60000 0x20>; + samsung,i2s-epll-clock-frequency = <192000000>; + samsung,i2s-sampling-rate = <48000>; + samsung,i2s-bits-per-sample = <16>; + samsung,i2s-channels = <2>; + samsung,i2s-lr-clk-framesize = <256>; + samsung,i2s-bit-clk-framesize = <32>; + samsung,i2s-id = <1>; };
spi@12d20000 { diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index 80ffe30..ec4c1c5 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -36,6 +36,7 @@ mmc3 = "/mmc@12230000"; serial0 = "/serial@12C30000"; console = "/serial@12C30000"; + i2s = "/sound@3830000"; };
sromc@12250000 { @@ -49,16 +50,14 @@ }; };
- sound@12d60000 { - samsung,i2s-epll-clock-frequency = <192000000>; - samsung,i2s-sampling-rate = <48000>; - samsung,i2s-bits-per-sample = <16>; - samsung,i2s-channels = <2>; - samsung,i2s-lr-clk-framesize = <256>; - samsung,i2s-bit-clk-framesize = <32>; + sound@3830000 { samsung,codec-type = "wm8994"; };
+ sound@12d60000 { + status = "disabled"; + }; + i2c@12c70000 { soundcodec@1a { reg = <0x1a>; diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts index dca3386..b97312f 100644 --- a/board/samsung/dts/exynos5250-snow.dts +++ b/board/samsung/dts/exynos5250-snow.dts @@ -36,6 +36,7 @@ mmc3 = "/mmc@12230000"; serial0 = "/serial@12C30000"; console = "/serial@12C30000"; + i2s = "/sound@3830000"; };
i2c4: i2c@12ca0000 { @@ -65,16 +66,15 @@ }; };
- sound@12d60000 { - samsung,i2s-epll-clock-frequency = <192000000>; - samsung,i2s-sampling-rate = <48000>; - samsung,i2s-bits-per-sample = <16>; - samsung,i2s-channels = <2>; - samsung,i2s-lr-clk-framesize = <256>; - samsung,i2s-bit-clk-framesize = <32>; + sound@3830000 { samsung,codec-type = "max98095"; + codec-enable-gpio = <&gpio 0xb7 0>; };
+ sound@12d60000 { + status = "disabled"; + }; + i2c@12cd0000 { soundcodec@22 { reg = <0x22>;

This patch makes the necessary changes for making use of I2S0 channel instead of I2S1 channel on smdk board. This changes are done to maintain the uniformity to use I2S0 channel.
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com --- arch/arm/cpu/armv7/exynos/clock.c | 57 ++++++++++++++++++++++------- arch/arm/cpu/armv7/exynos/pinmux.c | 15 +++++++- arch/arm/include/asm/arch-exynos/clk.h | 5 ++- arch/arm/include/asm/arch-exynos/clock.h | 4 ++ arch/arm/include/asm/arch-exynos/cpu.h | 4 ++ arch/arm/include/asm/arch-exynos/periph.h | 1 + drivers/sound/samsung-i2s.c | 14 +++---- 7 files changed, 75 insertions(+), 25 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 0cb1a61..80ed282 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -282,6 +282,9 @@ static unsigned long exynos5_get_periph_rate(int peripheral) src = readl(&clk->src_peric0); div = readl(&clk->div_peric3); break; + case PERIPH_ID_I2S0: + src = readl(&clk->src_mau); + div = readl(&clk->div_mau); case PERIPH_ID_SPI0: case PERIPH_ID_SPI1: src = readl(&clk->src_peric1); @@ -1146,17 +1149,29 @@ int exynos5_set_epll_clk(unsigned long rate) return 0; }
-void exynos5_set_i2s_clk_source(void) +void exynos5_set_i2s_clk_source(unsigned int i2s_id) { struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); - - clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, - (CLK_SRC_SCLK_EPLL)); + unsigned int *audio_ass = (unsigned int *)samsung_get_base_audio_ass(); + + if(i2s_id == 0) + { + setbits_le32(&clk->src_top2, CLK_SRC_MOUT_EPLL); + clrsetbits_le32(&clk->src_mau, AUDIO0_SEL_MASK, + (CLK_SRC_SCLK_EPLL)); + setbits_le32(audio_ass, AUDIO_CLKMUX_ASS); + } + else if(i2s_id == 1) + { + clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, + (CLK_SRC_SCLK_EPLL)); + } }
int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, - unsigned int dst_frq) + unsigned int dst_frq, + unsigned int i2s_id) { struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); @@ -1169,13 +1184,26 @@ int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, }
div = (src_frq / dst_frq); - if (div > AUDIO_1_RATIO_MASK) { - debug("%s: Frequency ratio is out of range\n", __func__); - debug("src frq = %d des frq = %d ", src_frq, dst_frq); - return -1; + if(i2s_id == 0) + { + if (div > AUDIO_0_RATIO_MASK) { + debug("%s: Frequency ratio is out of range\n", __func__); + debug("src frq = %d des frq = %d ", src_frq, dst_frq); + return -1; + } + clrsetbits_le32(&clk->div_mau, AUDIO_0_RATIO_MASK, + (div & AUDIO_0_RATIO_MASK)); } - clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, + else if(i2s_id == 1) + { + if (div > AUDIO_1_RATIO_MASK) { + debug("%s: Frequency ratio is out of range\n", __func__); + debug("src frq = %d des frq = %d ", src_frq, dst_frq); + return -1; + } + clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, (div & AUDIO_1_RATIO_MASK)); + } return 0; }
@@ -1415,19 +1443,20 @@ int set_spi_clk(int periph_id, unsigned int rate) return 0; }
-int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq, + unsigned int i2s_id) {
if (cpu_is_exynos5()) - return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq); + return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq, i2s_id); else return 0; }
-void set_i2s_clk_source(void) +void set_i2s_clk_source(unsigned int i2s_id) { if (cpu_is_exynos5()) - exynos5_set_i2s_clk_source(); + exynos5_set_i2s_clk_source(i2s_id); }
int set_epll_clk(unsigned long rate) diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 1b05ebf..6d1029e 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -221,9 +221,19 @@ static void exynos5_i2s_config(int peripheral) int i; struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); + struct exynos5_gpio_part4 *gpio4 = + (struct exynos5_gpio_part4 *) samsung_get_base_gpio_part4();
- for (i = 0; i < 5; i++) - s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02)); + switch (peripheral) { + case PERIPH_ID_I2S0: + for (i = 0; i < 5; i++) + s5p_gpio_cfg_pin(&gpio4->z, i, GPIO_FUNC(0x02)); + break; + case PERIPH_ID_I2S1: + for (i = 0; i < 5; i++) + s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02)); + break; + } }
void exynos5_spi_config(int peripheral) @@ -296,6 +306,7 @@ static int exynos5_pinmux_config(int peripheral, int flags) case PERIPH_ID_I2C7: exynos5_i2c_config(peripheral, flags); break; + case PERIPH_ID_I2S0: case PERIPH_ID_I2S1: exynos5_i2s_config(peripheral); break; diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 71075bd..a240ec7 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -31,8 +31,9 @@ void set_mmc_clk(int dev_index, unsigned int div); unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); -void set_i2s_clk_source(void); -int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +void set_i2s_clk_source(unsigned int i2s_id); +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq, + unsigned int i2s_id); int set_epll_clk(unsigned long rate); int set_spi_clk(int periph_id, unsigned int rate);
diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index 2b97b9a..cf26eef 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -876,8 +876,12 @@ struct set_epll_con_val { #define AUDIO_0_RATIO_MASK 0x0f #define AUDIO_1_RATIO_MASK 0x0f
+#define AUDIO0_SEL_MASK 0xf #define AUDIO1_SEL_MASK 0xf + #define CLK_SRC_SCLK_EPLL 0x7 +#define CLK_SRC_MOUT_EPLL (1<<12) +#define AUDIO_CLKMUX_ASS (1<<0)
/* CON0 bit-fields */ #define EPLL_CON0_MDIV_MASK 0x1ff diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index cb924fb..4b67191 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -50,6 +50,7 @@ #define EXYNOS4_SPI_ISP_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_ACE_SFR_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_DMC_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS4X12 */ #define EXYNOS4X12_GPIO_PART3_BASE 0x03860000 @@ -85,10 +86,12 @@ #define EXYNOS4X12_SPI_ISP_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_ACE_SFR_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_DMC_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4X12_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS5 Common*/ #define EXYNOS5_I2C_SPACING 0x10000
+#define EXYNOS5_AUDIOSS_BASE 0x03810000 #define EXYNOS5_GPIO_PART4_BASE 0x03860000 #define EXYNOS5_PRO_ID 0x10000000 #define EXYNOS5_CLOCK_BASE 0x10010000 @@ -226,6 +229,7 @@ SAMSUNG_BASE(spi_isp, SPI_ISP_BASE) SAMSUNG_BASE(tzpc, TZPC_BASE) SAMSUNG_BASE(dmc_ctrl, DMC_CTRL_BASE) SAMSUNG_BASE(dmc_phy, DMC_PHY_BASE) +SAMSUNG_BASE(audio_ass, AUDIOSS_BASE) #endif
#endif /* _EXYNOS4_CPU_H */ diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 9952155..64bd8b7 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -34,6 +34,7 @@ enum periph_id { PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2, PERIPH_ID_SDMMC3, + PERIPH_ID_I2S0 = 98, PERIPH_ID_I2S1 = 99,
/* Since following peripherals do diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c index 49921e5..9caa4d2 100644 --- a/drivers/sound/samsung-i2s.c +++ b/drivers/sound/samsung-i2s.c @@ -67,7 +67,6 @@ static void i2s_txctrl(struct i2s_reg *i2s_reg, int on) con &= ~CON_TXCH_PAUSE;
} else { - con |= CON_TXCH_PAUSE; con &= ~CON_ACTIVE; } @@ -172,7 +171,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid format priority [0x%x]\n", __func__, - (fmt & SND_SOC_DAIFMT_FORMAT_MASK)); + (fmt & SND_SOC_DAIFMT_FORMAT_MASK)); return -1; }
@@ -191,7 +190,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid clock ploarity input [0x%x]\n", __func__, - (fmt & SND_SOC_DAIFMT_INV_MASK)); + (fmt & SND_SOC_DAIFMT_INV_MASK)); return -1; }
@@ -209,7 +208,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid master selection [0x%x]\n", __func__, - (fmt & SND_SOC_DAIFMT_MASTER_MASK)); + (fmt & SND_SOC_DAIFMT_MASTER_MASK)); return -1; }
@@ -250,7 +249,7 @@ int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) break; default: debug("%s: Invalid sample size input [0x%x]\n", - __func__, blc); + __func__, blc); return -1; } writel(mod, &i2s_reg->mod); @@ -313,11 +312,12 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx) }
/* Select Clk Source for Audio1 */ - set_i2s_clk_source(); + set_i2s_clk_source(pi2s_tx->id);
/* Set Prescaler to get MCLK */ set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, - (pi2s_tx->samplingrate * (pi2s_tx->rfs))); + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->id);
/* Configure I2s format */ ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |

Hi Dani,
You refer to http://www.denx.de/wiki/U-Boot/CodingStyle
And cc'd Minkyu.
On 09/11/2013 12:02 AM, Dani Krishna Mohan wrote:
This patch makes the necessary changes for making use of I2S0 channel instead of I2S1 channel on smdk board. This changes are done to maintain the uniformity to use I2S0 channel.
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com
arch/arm/cpu/armv7/exynos/clock.c | 57 ++++++++++++++++++++++------- arch/arm/cpu/armv7/exynos/pinmux.c | 15 +++++++- arch/arm/include/asm/arch-exynos/clk.h | 5 ++- arch/arm/include/asm/arch-exynos/clock.h | 4 ++ arch/arm/include/asm/arch-exynos/cpu.h | 4 ++ arch/arm/include/asm/arch-exynos/periph.h | 1 + drivers/sound/samsung-i2s.c | 14 +++---- 7 files changed, 75 insertions(+), 25 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 0cb1a61..80ed282 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -282,6 +282,9 @@ static unsigned long exynos5_get_periph_rate(int peripheral) src = readl(&clk->src_peric0); div = readl(&clk->div_peric3); break;
- case PERIPH_ID_I2S0:
src = readl(&clk->src_mau);
case PERIPH_ID_SPI0: case PERIPH_ID_SPI1: src = readl(&clk->src_peric1);div = readl(&clk->div_mau);
@@ -1146,17 +1149,29 @@ int exynos5_set_epll_clk(unsigned long rate) return 0; }
-void exynos5_set_i2s_clk_source(void) +void exynos5_set_i2s_clk_source(unsigned int i2s_id) { struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock();
- clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
(CLK_SRC_SCLK_EPLL));
- unsigned int *audio_ass = (unsigned int *)samsung_get_base_audio_ass();
- if(i2s_id == 0)
- {
setbits_le32(&clk->src_top2, CLK_SRC_MOUT_EPLL);
clrsetbits_le32(&clk->src_mau, AUDIO0_SEL_MASK,
(CLK_SRC_SCLK_EPLL));
setbits_le32(audio_ass, AUDIO_CLKMUX_ASS);
- }
- else if(i2s_id == 1)
- {
clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
(CLK_SRC_SCLK_EPLL));
- }
Can i2c_id get other value beside 0 or 1? And Could you change the coding style.
}
int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
unsigned int dst_frq)
unsigned int dst_frq,
unsigned int i2s_id)
{ struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); @@ -1169,13 +1184,26 @@ int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, }
div = (src_frq / dst_frq);
- if (div > AUDIO_1_RATIO_MASK) {
debug("%s: Frequency ratio is out of range\n", __func__);
debug("src frq = %d des frq = %d ", src_frq, dst_frq);
return -1;
- if(i2s_id == 0)
- {
if (div > AUDIO_0_RATIO_MASK) {
debug("%s: Frequency ratio is out of range\n", __func__);
debug("src frq = %d des frq = %d ", src_frq, dst_frq);
return -1;
}
clrsetbits_le32(&clk->div_mau, AUDIO_0_RATIO_MASK,
}(div & AUDIO_0_RATIO_MASK));
- clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
- else if(i2s_id == 1)
- {
if (div > AUDIO_1_RATIO_MASK) {
debug("%s: Frequency ratio is out of range\n", __func__);
debug("src frq = %d des frq = %d ", src_frq, dst_frq);
return -1;
}
clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, (div & AUDIO_1_RATIO_MASK));
- }
Ditto.
return 0; }
@@ -1415,19 +1443,20 @@ int set_spi_clk(int periph_id, unsigned int rate) return 0; }
-int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq,
unsigned int i2s_id)
{
if (cpu_is_exynos5())
return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
else return 0;return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq, i2s_id);
}
-void set_i2s_clk_source(void) +void set_i2s_clk_source(unsigned int i2s_id) { if (cpu_is_exynos5())
exynos5_set_i2s_clk_source();
exynos5_set_i2s_clk_source(i2s_id);
}
int set_epll_clk(unsigned long rate) diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 1b05ebf..6d1029e 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -221,9 +221,19 @@ static void exynos5_i2s_config(int peripheral) int i; struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1();
- struct exynos5_gpio_part4 *gpio4 =
(struct exynos5_gpio_part4 *) samsung_get_base_gpio_part4();
- for (i = 0; i < 5; i++)
s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02));
- switch (peripheral) {
- case PERIPH_ID_I2S0:
for (i = 0; i < 5; i++)
s5p_gpio_cfg_pin(&gpio4->z, i, GPIO_FUNC(0x02));
break;
- case PERIPH_ID_I2S1:
for (i = 0; i < 5; i++)
s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02));
break;
- }
}
void exynos5_spi_config(int peripheral) @@ -296,6 +306,7 @@ static int exynos5_pinmux_config(int peripheral, int flags) case PERIPH_ID_I2C7: exynos5_i2c_config(peripheral, flags); break;
- case PERIPH_ID_I2S0: case PERIPH_ID_I2S1: exynos5_i2s_config(peripheral); break;
diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 71075bd..a240ec7 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -31,8 +31,9 @@ void set_mmc_clk(int dev_index, unsigned int div); unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); -void set_i2s_clk_source(void); -int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +void set_i2s_clk_source(unsigned int i2s_id); +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq,
unsigned int i2s_id);
int set_epll_clk(unsigned long rate); int set_spi_clk(int periph_id, unsigned int rate);
diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index 2b97b9a..cf26eef 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -876,8 +876,12 @@ struct set_epll_con_val { #define AUDIO_0_RATIO_MASK 0x0f #define AUDIO_1_RATIO_MASK 0x0f
+#define AUDIO0_SEL_MASK 0xf #define AUDIO1_SEL_MASK 0xf
#define CLK_SRC_SCLK_EPLL 0x7 +#define CLK_SRC_MOUT_EPLL (1<<12) +#define AUDIO_CLKMUX_ASS (1<<0)
/* CON0 bit-fields */ #define EPLL_CON0_MDIV_MASK 0x1ff diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index cb924fb..4b67191 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -50,6 +50,7 @@ #define EXYNOS4_SPI_ISP_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_ACE_SFR_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_DMC_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS4X12 */ #define EXYNOS4X12_GPIO_PART3_BASE 0x03860000 @@ -85,10 +86,12 @@ #define EXYNOS4X12_SPI_ISP_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_ACE_SFR_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_DMC_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4X12_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS5 Common*/ #define EXYNOS5_I2C_SPACING 0x10000
+#define EXYNOS5_AUDIOSS_BASE 0x03810000 #define EXYNOS5_GPIO_PART4_BASE 0x03860000 #define EXYNOS5_PRO_ID 0x10000000 #define EXYNOS5_CLOCK_BASE 0x10010000 @@ -226,6 +229,7 @@ SAMSUNG_BASE(spi_isp, SPI_ISP_BASE) SAMSUNG_BASE(tzpc, TZPC_BASE) SAMSUNG_BASE(dmc_ctrl, DMC_CTRL_BASE) SAMSUNG_BASE(dmc_phy, DMC_PHY_BASE) +SAMSUNG_BASE(audio_ass, AUDIOSS_BASE) #endif
#endif /* _EXYNOS4_CPU_H */ diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 9952155..64bd8b7 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -34,6 +34,7 @@ enum periph_id { PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2, PERIPH_ID_SDMMC3,
PERIPH_ID_I2S0 = 98, PERIPH_ID_I2S1 = 99,
/* Since following peripherals do
diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c index 49921e5..9caa4d2 100644 --- a/drivers/sound/samsung-i2s.c +++ b/drivers/sound/samsung-i2s.c @@ -67,7 +67,6 @@ static void i2s_txctrl(struct i2s_reg *i2s_reg, int on) con &= ~CON_TXCH_PAUSE;
} else {
- con |= CON_TXCH_PAUSE; con &= ~CON_ACTIVE; }
@@ -172,7 +171,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid format priority [0x%x]\n", __func__,
(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
return -1; }(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
@@ -191,7 +190,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
(fmt & SND_SOC_DAIFMT_INV_MASK));
return -1; }(fmt & SND_SOC_DAIFMT_INV_MASK));
@@ -209,7 +208,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid master selection [0x%x]\n", __func__,
(fmt & SND_SOC_DAIFMT_MASTER_MASK));
return -1; }(fmt & SND_SOC_DAIFMT_MASTER_MASK));
@@ -250,7 +249,7 @@ int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) break; default: debug("%s: Invalid sample size input [0x%x]\n",
__func__, blc);
return -1; } writel(mod, &i2s_reg->mod);__func__, blc);
@@ -313,11 +312,12 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx) }
/* Select Clk Source for Audio1 */
- set_i2s_clk_source();
set_i2s_clk_source(pi2s_tx->id);
/* Set Prescaler to get MCLK */ set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk,
(pi2s_tx->samplingrate * (pi2s_tx->rfs)));
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
pi2s_tx->id);
/* Configure I2s format */ ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |

Hello Mr Jaehoon, I have done the changes as suggested by you and resubmitted all 5 patches. Request you to verify them and let me know if there are any issues.
Regards, -Krishna
-------------------------------------------------- From: "Jaehoon Chung" jh80.chung@samsung.com Sent: Wednesday, September 11, 2013 6:09 AM To: "Dani Krishna Mohan" krishna.md@samsung.com Cc: u-boot@lists.denx.de; rajeshwari.s@samsung.com; "Minkyu Kang" mk7.kang@samsung.com Subject: Re: [U-Boot] [PATCH V2 3/5] ARM: Added I2S0 clocks for audio
Hi Dani,
You refer to http://www.denx.de/wiki/U-Boot/CodingStyle
And cc'd Minkyu.
On 09/11/2013 12:02 AM, Dani Krishna Mohan wrote:
This patch makes the necessary changes for making use of I2S0 channel instead of I2S1 channel on smdk board. This changes are done to maintain the uniformity to use I2S0 channel.
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com
arch/arm/cpu/armv7/exynos/clock.c | 57 ++++++++++++++++++++++------- arch/arm/cpu/armv7/exynos/pinmux.c | 15 +++++++- arch/arm/include/asm/arch-exynos/clk.h | 5 ++- arch/arm/include/asm/arch-exynos/clock.h | 4 ++ arch/arm/include/asm/arch-exynos/cpu.h | 4 ++ arch/arm/include/asm/arch-exynos/periph.h | 1 + drivers/sound/samsung-i2s.c | 14 +++---- 7 files changed, 75 insertions(+), 25 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 0cb1a61..80ed282 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -282,6 +282,9 @@ static unsigned long exynos5_get_periph_rate(int peripheral) src = readl(&clk->src_peric0); div = readl(&clk->div_peric3); break;
- case PERIPH_ID_I2S0:
- src = readl(&clk->src_mau);
- div = readl(&clk->div_mau);
case PERIPH_ID_SPI0: case PERIPH_ID_SPI1: src = readl(&clk->src_peric1); @@ -1146,17 +1149,29 @@ int exynos5_set_epll_clk(unsigned long rate) return 0; }
-void exynos5_set_i2s_clk_source(void) +void exynos5_set_i2s_clk_source(unsigned int i2s_id) { struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock();
- clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
- (CLK_SRC_SCLK_EPLL));
- unsigned int *audio_ass = (unsigned int *)samsung_get_base_audio_ass();
- if(i2s_id == 0)
- {
- setbits_le32(&clk->src_top2, CLK_SRC_MOUT_EPLL);
- clrsetbits_le32(&clk->src_mau, AUDIO0_SEL_MASK,
- (CLK_SRC_SCLK_EPLL));
- setbits_le32(audio_ass, AUDIO_CLKMUX_ASS);
- }
- else if(i2s_id == 1)
- {
- clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
- (CLK_SRC_SCLK_EPLL));
- }
Can i2c_id get other value beside 0 or 1? And Could you change the coding style.
}
int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
- unsigned int dst_frq)
- unsigned int dst_frq,
- unsigned int i2s_id)
{ struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); @@ -1169,13 +1184,26 @@ int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, }
div = (src_frq / dst_frq);
- if (div > AUDIO_1_RATIO_MASK) {
- debug("%s: Frequency ratio is out of range\n", __func__);
- debug("src frq = %d des frq = %d ", src_frq, dst_frq);
- return -1;
- if(i2s_id == 0)
- {
- if (div > AUDIO_0_RATIO_MASK) {
- debug("%s: Frequency ratio is out of range\n", __func__);
- debug("src frq = %d des frq = %d ", src_frq, dst_frq);
- return -1;
- }
- clrsetbits_le32(&clk->div_mau, AUDIO_0_RATIO_MASK,
- (div & AUDIO_0_RATIO_MASK));
}
- clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
- else if(i2s_id == 1)
- {
- if (div > AUDIO_1_RATIO_MASK) {
- debug("%s: Frequency ratio is out of range\n", __func__);
- debug("src frq = %d des frq = %d ", src_frq, dst_frq);
- return -1;
- }
- clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
(div & AUDIO_1_RATIO_MASK));
- }
Ditto.
return 0; }
@@ -1415,19 +1443,20 @@ int set_spi_clk(int periph_id, unsigned int rate) return 0; }
-int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq,
- unsigned int i2s_id)
{
if (cpu_is_exynos5())
- return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
- return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq, i2s_id);
else return 0; }
-void set_i2s_clk_source(void) +void set_i2s_clk_source(unsigned int i2s_id) { if (cpu_is_exynos5())
- exynos5_set_i2s_clk_source();
- exynos5_set_i2s_clk_source(i2s_id);
}
int set_epll_clk(unsigned long rate) diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 1b05ebf..6d1029e 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -221,9 +221,19 @@ static void exynos5_i2s_config(int peripheral) int i; struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1();
- struct exynos5_gpio_part4 *gpio4 =
- (struct exynos5_gpio_part4 *) samsung_get_base_gpio_part4();
- for (i = 0; i < 5; i++)
- s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02));
- switch (peripheral) {
- case PERIPH_ID_I2S0:
- for (i = 0; i < 5; i++)
- s5p_gpio_cfg_pin(&gpio4->z, i, GPIO_FUNC(0x02));
- break;
- case PERIPH_ID_I2S1:
- for (i = 0; i < 5; i++)
- s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02));
- break;
- }
}
void exynos5_spi_config(int peripheral) @@ -296,6 +306,7 @@ static int exynos5_pinmux_config(int peripheral, int flags) case PERIPH_ID_I2C7: exynos5_i2c_config(peripheral, flags); break;
- case PERIPH_ID_I2S0:
case PERIPH_ID_I2S1: exynos5_i2s_config(peripheral); break; diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 71075bd..a240ec7 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -31,8 +31,9 @@ void set_mmc_clk(int dev_index, unsigned int div); unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); -void set_i2s_clk_source(void); -int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +void set_i2s_clk_source(unsigned int i2s_id); +int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq,
- unsigned int i2s_id);
int set_epll_clk(unsigned long rate); int set_spi_clk(int periph_id, unsigned int rate);
diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index 2b97b9a..cf26eef 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -876,8 +876,12 @@ struct set_epll_con_val { #define AUDIO_0_RATIO_MASK 0x0f #define AUDIO_1_RATIO_MASK 0x0f
+#define AUDIO0_SEL_MASK 0xf #define AUDIO1_SEL_MASK 0xf
#define CLK_SRC_SCLK_EPLL 0x7 +#define CLK_SRC_MOUT_EPLL (1<<12) +#define AUDIO_CLKMUX_ASS (1<<0)
/* CON0 bit-fields */ #define EPLL_CON0_MDIV_MASK 0x1ff diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index cb924fb..4b67191 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -50,6 +50,7 @@ #define EXYNOS4_SPI_ISP_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_ACE_SFR_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_DMC_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS4X12 */ #define EXYNOS4X12_GPIO_PART3_BASE 0x03860000 @@ -85,10 +86,12 @@ #define EXYNOS4X12_SPI_ISP_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_ACE_SFR_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4X12_DMC_PHY_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS4X12_AUDIOSS_BASE DEVICE_NOT_AVAILABLE
/* EXYNOS5 Common*/ #define EXYNOS5_I2C_SPACING 0x10000
+#define EXYNOS5_AUDIOSS_BASE 0x03810000 #define EXYNOS5_GPIO_PART4_BASE 0x03860000 #define EXYNOS5_PRO_ID 0x10000000 #define EXYNOS5_CLOCK_BASE 0x10010000 @@ -226,6 +229,7 @@ SAMSUNG_BASE(spi_isp, SPI_ISP_BASE) SAMSUNG_BASE(tzpc, TZPC_BASE) SAMSUNG_BASE(dmc_ctrl, DMC_CTRL_BASE) SAMSUNG_BASE(dmc_phy, DMC_PHY_BASE) +SAMSUNG_BASE(audio_ass, AUDIOSS_BASE) #endif
#endif /* _EXYNOS4_CPU_H */ diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 9952155..64bd8b7 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -34,6 +34,7 @@ enum periph_id { PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2, PERIPH_ID_SDMMC3,
- PERIPH_ID_I2S0 = 98,
PERIPH_ID_I2S1 = 99,
/* Since following peripherals do diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c index 49921e5..9caa4d2 100644 --- a/drivers/sound/samsung-i2s.c +++ b/drivers/sound/samsung-i2s.c @@ -67,7 +67,6 @@ static void i2s_txctrl(struct i2s_reg *i2s_reg, int on) con &= ~CON_TXCH_PAUSE;
} else {
con |= CON_TXCH_PAUSE; con &= ~CON_ACTIVE; } @@ -172,7 +171,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid format priority [0x%x]\n", __func__,
- (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
return -1; }
@@ -191,7 +190,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
- (fmt & SND_SOC_DAIFMT_INV_MASK));
(fmt & SND_SOC_DAIFMT_INV_MASK));
return -1; }
@@ -209,7 +208,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) break; default: debug("%s: Invalid master selection [0x%x]\n", __func__,
- (fmt & SND_SOC_DAIFMT_MASTER_MASK));
(fmt & SND_SOC_DAIFMT_MASTER_MASK));
return -1; }
@@ -250,7 +249,7 @@ int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) break; default: debug("%s: Invalid sample size input [0x%x]\n",
- __func__, blc);
__func__, blc);
return -1; } writel(mod, &i2s_reg->mod); @@ -313,11 +312,12 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx) }
/* Select Clk Source for Audio1 */
- set_i2s_clk_source();
- set_i2s_clk_source(pi2s_tx->id);
/* Set Prescaler to get MCLK */ set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk,
- (pi2s_tx->samplingrate * (pi2s_tx->rfs)));
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
pi2s_tx->id);
/* Configure I2s format */ ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |

This patch makes required changes to make use of I2S0 channel instead of I2S1 channel on exynos5250.
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com --- arch/arm/include/asm/arch-exynos/i2s-regs.h | 6 ++++ drivers/sound/samsung-i2s.c | 42 +++++++++++++++++++-------- 2 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/arch/arm/include/asm/arch-exynos/i2s-regs.h b/arch/arm/include/asm/arch-exynos/i2s-regs.h index 613b9b7..4a4a7a0 100644 --- a/arch/arm/include/asm/arch-exynos/i2s-regs.h +++ b/arch/arm/include/asm/arch-exynos/i2s-regs.h @@ -8,10 +8,12 @@ #ifndef __I2S_REGS_H__ #define __I2S_REGS_H__
+#define CON_RESET (1 << 31) #define CON_TXFIFO_FULL (1 << 8) #define CON_TXCH_PAUSE (1 << 4) #define CON_ACTIVE (1 << 0)
+#define MOD_OP_CLK (3 << 30) #define MOD_BLCP_SHIFT 24 #define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT) #define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT) @@ -24,6 +26,7 @@ #define MOD_BLC_MASK (3 << 13)
#define MOD_SLAVE (1 << 11) +#define MOD_RCLKSRC (0 << 10) #define MOD_MASK (3 << 8) #define MOD_LR_LLOW (0 << 7) #define MOD_LR_RLOW (1 << 7) @@ -47,4 +50,7 @@ #define FIC_TXFLUSH (1 << 15) #define FIC_RXFLUSH (1 << 7)
+#define PSREN (1 << 15) +#define PSVAL (3 << 8) + #endif /* __I2S_REGS_H__ */ diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c index 9caa4d2..66db9a8 100644 --- a/drivers/sound/samsung-i2s.c +++ b/drivers/sound/samsung-i2s.c @@ -65,7 +65,6 @@ static void i2s_txctrl(struct i2s_reg *i2s_reg, int on) if (on) { con |= CON_ACTIVE; con &= ~CON_TXCH_PAUSE; - } else { con |= CON_TXCH_PAUSE; con &= ~CON_ACTIVE; @@ -300,28 +299,47 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx) int ret; struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address; + if (pi2s_tx->id == 0) { + /* Initialize GPIO for I2S-0 */ + exynos_pinmux_config(PERIPH_ID_I2S0, 0); + + /* Set EPLL Clock */ + ret = set_epll_clk(pi2s_tx->samplingrate * pi2s_tx->rfs * 4); + } else if (pi2s_tx->id == 1) { + /* Initialize GPIO for I2S-1 */ + exynos_pinmux_config(PERIPH_ID_I2S1, 0); + + /* Set EPLL Clock */ + ret = set_epll_clk(pi2s_tx->audio_pll_clk); + } else { + debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id); + return -1; + }
- /* Initialize GPIO for I2s */ - exynos_pinmux_config(PERIPH_ID_I2S1, 0); - - /* Set EPLL Clock */ - ret = set_epll_clk(pi2s_tx->audio_pll_clk); if (ret != 0) { debug("%s: epll clock set rate falied\n", __func__); return -1; }
- /* Select Clk Source for Audio1 */ + /* Select Clk Source for Audio 0 or 1 */ set_i2s_clk_source(pi2s_tx->id);
- /* Set Prescaler to get MCLK */ - set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, - (pi2s_tx->samplingrate * (pi2s_tx->rfs)), - pi2s_tx->id); + if (pi2s_tx->id == 0) { + /*Reset the i2s module */ + writel(CON_RESET, &i2s_reg->con);
+ writel(MOD_OP_CLK | MOD_RCLKSRC, &i2s_reg->mod); + /* set i2s prescaler */ + writel(PSREN | PSVAL, &i2s_reg->psr); + } else { + /* Set Prescaler to get MCLK */ + set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->id); + } /* Configure I2s format */ ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM)); + SND_SOC_DAIFMT_CBM_CFM)); if (ret == 0) { i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs); ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);

This patch modifies the MAX98095 audio codec to support I2S0 channel in codec slave mode.
Signed-off-by: Dani Krishna Mohan krishna.md@samsung.com --- drivers/sound/max98095.c | 128 ++++++++++++++++++++++++++++++---------------- drivers/sound/max98095.h | 10 +++- drivers/sound/sound.c | 17 +++--- 3 files changed, 100 insertions(+), 55 deletions(-)
diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c index d69db58..f7ec4d7 100644 --- a/drivers/sound/max98095.c +++ b/drivers/sound/max98095.c @@ -52,7 +52,7 @@ int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, static int max98095_i2c_write(unsigned int reg, unsigned char data) { debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n", - __func__, reg, data); + __func__, reg, data); return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1); }
@@ -71,7 +71,7 @@ static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data) ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1); if (ret != 0) { debug("%s: Error while reading register %#04x\n", - __func__, reg); + __func__, reg); return -1; }
@@ -138,42 +138,56 @@ static int rate_value(int rate, u8 *value) * @return -1 for error and 0 Success. */ static int max98095_hw_params(struct max98095_priv *max98095, - unsigned int rate, unsigned int bits_per_sample) + enum en_max_audio_interface aif_id, + unsigned int rate, unsigned int bits_per_sample) { u8 regval; int error; + unsigned short M98095_DAI_CLKMODE; + unsigned short M98095_DAI_FORMAT; + unsigned short M98095_DAI_FILTERS; + + if (aif_id == AIF1) { + M98095_DAI_CLKMODE = M98095_027_DAI1_CLKMODE; + M98095_DAI_FORMAT = M98095_02A_DAI1_FORMAT; + M98095_DAI_FILTERS = M98095_02E_DAI1_FILTERS; + } else { + M98095_DAI_CLKMODE = M98095_031_DAI2_CLKMODE; + M98095_DAI_FORMAT = M98095_034_DAI2_FORMAT; + M98095_DAI_FILTERS = M98095_038_DAI2_FILTERS; + }
switch (bits_per_sample) { case 16: - error = max98095_update_bits(M98095_034_DAI2_FORMAT, + error = max98095_update_bits(M98095_DAI_FORMAT, M98095_DAI_WS, 0); break; case 24: - error = max98095_update_bits(M98095_034_DAI2_FORMAT, + error = max98095_update_bits(M98095_DAI_FORMAT, M98095_DAI_WS, M98095_DAI_WS); break; default: debug("%s: Illegal bits per sample %d.\n", - __func__, bits_per_sample); + __func__, bits_per_sample); return -1; }
if (rate_value(rate, ®val)) { debug("%s: Failed to set sample rate to %d.\n", - __func__, rate); + __func__, rate); return -1; } max98095->rate = rate;
- error |= max98095_update_bits(M98095_031_DAI2_CLKMODE, + error |= max98095_update_bits(M98095_DAI_CLKMODE, M98095_CLKMODE_MASK, regval);
/* Update sample rate mode */ if (rate < 50000) - error |= max98095_update_bits(M98095_038_DAI2_FILTERS, + error |= max98095_update_bits(M98095_DAI_FILTERS, M98095_DAI_DHF, 0); else - error |= max98095_update_bits(M98095_038_DAI2_FILTERS, + error |= max98095_update_bits(M98095_DAI_FILTERS, M98095_DAI_DHF, M98095_DAI_DHF);
if (error < 0) { @@ -235,22 +249,39 @@ static int max98095_set_sysclk(struct max98095_priv *max98095, * * @return -1 for error and 0 Success. */ -static int max98095_set_fmt(struct max98095_priv *max98095, int fmt) +static int max98095_set_fmt(struct max98095_priv *max98095, int fmt, + enum en_max_audio_interface aif_id) { u8 regval = 0; int error = 0; + unsigned short M98095_DAI_CLKCFG_HI; + unsigned short M98095_DAI_CLKCFG_LO; + unsigned short M98095_DAI_FORMAT; + unsigned short M98095_DAI_CLOCK;
if (fmt == max98095->fmt) return 0;
max98095->fmt = fmt;
+ if (aif_id == AIF1) { + M98095_DAI_CLKCFG_HI = M98095_028_DAI1_CLKCFG_HI; + M98095_DAI_CLKCFG_LO = M98095_029_DAI1_CLKCFG_LO; + M98095_DAI_FORMAT = M98095_02A_DAI1_FORMAT; + M98095_DAI_CLOCK = M98095_02B_DAI1_CLOCK; + } else { + M98095_DAI_CLKCFG_HI = M98095_032_DAI2_CLKCFG_HI; + M98095_DAI_CLKCFG_LO = M98095_033_DAI2_CLKCFG_LO; + M98095_DAI_FORMAT = M98095_034_DAI2_FORMAT; + M98095_DAI_CLOCK = M98095_035_DAI2_CLOCK; + } + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* Slave mode PLL */ - error |= max98095_i2c_write(M98095_032_DAI2_CLKCFG_HI, + error |= max98095_i2c_write(M98095_DAI_CLKCFG_HI, 0x80); - error |= max98095_i2c_write(M98095_033_DAI2_CLKCFG_LO, + error |= max98095_i2c_write(M98095_DAI_CLKCFG_LO, 0x00); break; case SND_SOC_DAIFMT_CBM_CFM: @@ -292,11 +323,11 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt) return -1; }
- error |= max98095_update_bits(M98095_034_DAI2_FORMAT, + error |= max98095_update_bits(M98095_DAI_FORMAT, M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | M98095_DAI_WCI, regval);
- error |= max98095_i2c_write(M98095_035_DAI2_CLOCK, + error |= max98095_i2c_write(M98095_DAI_CLOCK, M98095_DAI_BSEL64);
if (error < 0) { @@ -354,7 +385,8 @@ static int max98095_reset(void) * * @returns -1 for error and 0 Success. */ -static int max98095_device_init(struct max98095_priv *max98095) +static int max98095_device_init(struct max98095_priv *max98095, + enum en_max_audio_interface aif_id) { unsigned char id; int error = 0; @@ -374,7 +406,7 @@ static int max98095_device_init(struct max98095_priv *max98095) error = max98095_i2c_read(M98095_0FF_REV_ID, &id); if (error < 0) { debug("%s: Failure reading hardware revision: %d\n", - __func__, id); + __func__, id); goto err_access; } debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A'); @@ -385,22 +417,22 @@ static int max98095_device_init(struct max98095_priv *max98095) * initialize registers to hardware default configuring audio * interface2 to DAC */ - error |= max98095_i2c_write(M98095_048_MIX_DAC_LR, - M98095_DAI2M_TO_DACL|M98095_DAI2M_TO_DACR); + if (aif_id == AIF1) + error |= max98095_i2c_write(M98095_048_MIX_DAC_LR, + M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); + else + error |= max98095_i2c_write(M98095_048_MIX_DAC_LR, + M98095_DAI2M_TO_DACL|M98095_DAI2M_TO_DACR);
error |= max98095_i2c_write(M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM); - error |= max98095_i2c_write(M98095_045_CFG_DSP, M98095_DSPNORMAL); error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL); - - error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG, - M98095_S1NORMAL|M98095_SDATA); - - error |= max98095_i2c_write(M98095_036_DAI2_IOCFG, - M98095_S2NORMAL|M98095_SDATA); - - error |= max98095_i2c_write(M98095_040_DAI3_IOCFG, - M98095_S3NORMAL|M98095_SDATA); + if (aif_id == AIF1) + error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG, + M98095_S1NORMAL|M98095_SDATA); + else + error |= max98095_i2c_write(M98095_036_DAI2_IOCFG, + M98095_S2NORMAL|M98095_SDATA);
/* take the codec out of the shut down */ error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN, @@ -422,7 +454,10 @@ static int max98095_device_init(struct max98095_priv *max98095)
/* Enable DAIs */ error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30); - error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07); + if (aif_id == AIF1) + error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x01); + else + error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
err_access: if (error < 0) @@ -432,8 +467,9 @@ err_access: }
static int max98095_do_init(struct sound_codec_info *pcodec_info, - int sampling_rate, int mclk_freq, - int bits_per_sample) + enum en_max_audio_interface aif_id, + int sampling_rate, int mclk_freq, + int bits_per_sample) { int ret = 0;
@@ -443,15 +479,15 @@ static int max98095_do_init(struct sound_codec_info *pcodec_info, /* shift the device address by 1 for 7 bit addressing */ g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
- if (pcodec_info->codec_type == CODEC_MAX_98095) + if (pcodec_info->codec_type == CODEC_MAX_98095) { g_max98095_info.devtype = MAX98095; - else { + } else { debug("%s: Codec id [%d] not defined\n", __func__, - pcodec_info->codec_type); + pcodec_info->codec_type); return -1; }
- ret = max98095_device_init(&g_max98095_info); + ret = max98095_device_init(&g_max98095_info, aif_id); if (ret < 0) { debug("%s: max98095 codec chip init failed\n", __func__); return ret; @@ -463,14 +499,15 @@ static int max98095_do_init(struct sound_codec_info *pcodec_info, return ret; }
- ret = max98095_hw_params(&g_max98095_info, sampling_rate, - bits_per_sample); + ret = max98095_hw_params(&g_max98095_info, aif_id, sampling_rate, + bits_per_sample);
if (ret == 0) { ret = max98095_set_fmt(&g_max98095_info, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + aif_id); }
return ret; @@ -529,8 +566,9 @@ static int get_max98095_codec_values(struct sound_codec_info *pcodec_info, }
/* max98095 Device Initialisation */ -int max98095_init(const void *blob, int sampling_rate, int mclk_freq, - int bits_per_sample) +int max98095_init(const void *blob, enum en_max_audio_interface aif_id, + int sampling_rate, int mclk_freq, + int bits_per_sample) { int ret; int old_bus = i2c_get_bus_num(); @@ -542,8 +580,8 @@ int max98095_init(const void *blob, int sampling_rate, int mclk_freq, }
i2c_set_bus_num(pcodec_info->i2c_bus); - ret = max98095_do_init(pcodec_info, sampling_rate, mclk_freq, - bits_per_sample); + ret = max98095_do_init(pcodec_info, aif_id, sampling_rate, mclk_freq, + bits_per_sample); i2c_set_bus_num(old_bus);
return ret; diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h index ae5eb14..44b1e3a 100644 --- a/drivers/sound/max98095.h +++ b/drivers/sound/max98095.h @@ -11,6 +11,12 @@ #ifndef _MAX98095_H #define _MAX98095_H
+/* Available audio interface ports in wm8994 codec */ +enum en_max_audio_interface { + AIF1 = 1, + AIF2, +}; + /* * MAX98095 Registers Definition */ @@ -305,7 +311,7 @@ * * @returns -1 for error and 0 Success. */ -int max98095_init(const void *blob, int sampling_rate, int mclk_freq, - int bits_per_sample); +int max98095_init(const void *blob, enum en_max_audio_interface aif_id, + int sampling_rate, int mclk_freq, int bits_per_sample);
#endif diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index f3342f2..9b8ce5a 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -116,7 +116,7 @@ static int codec_init(const void *blob, struct i2stx_info *pi2s_tx) int node;
/* Get the node from FDT for sound */ - 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"); debug("node = %d\n", node); @@ -136,13 +136,14 @@ static int codec_init(const void *blob, struct i2stx_info *pi2s_tx) if (!strcmp(codectype, "wm8994")) { /* Check the codec type and initialise the same */ ret = wm8994_init(blob, pi2s_tx->id + 1, - pi2s_tx->samplingrate, - (pi2s_tx->samplingrate * (pi2s_tx->rfs)), - pi2s_tx->bitspersample, pi2s_tx->channels); + 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)), - pi2s_tx->bitspersample); + ret = max98095_init(blob, pi2s_tx->id + 1, + pi2s_tx->samplingrate, + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->bitspersample); } else { debug("%s: Unknown codec type %s\n", __func__, codectype); return -1; @@ -235,7 +236,7 @@ int sound_play(uint32_t msec, uint32_t frequency) }
sound_prepare_buffer((unsigned short *)data, - data_size / sizeof(unsigned short), frequency); + data_size / sizeof(unsigned short), frequency);
while (msec >= 1000) { ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
participants (3)
-
D Krishna Mohan
-
Dani Krishna Mohan
-
Jaehoon Chung