diff options
-rw-r--r-- | arch/arm/cpu/armv7/exynos/clock.c | 61 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/exynos/pinmux.c | 23 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-exynos/clk.h | 5 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-exynos/clock.h | 4 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-exynos/cpu.h | 4 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-exynos/periph.h | 1 | ||||
-rw-r--r-- | drivers/sound/samsung-i2s.c | 26 |
7 files changed, 93 insertions, 31 deletions
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 0cb1a61..36fedd6 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) +int 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)); + } else { + return -1; + } + return 0; } 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,27 @@ 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); + 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)); + } 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)); + } else { return -1; } - clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, - (div & AUDIO_1_RATIO_MASK)); return 0; } @@ -1415,19 +1444,21 @@ 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) +int set_i2s_clk_source(unsigned int i2s_id) { if (cpu_is_exynos5()) - exynos5_set_i2s_clk_source(); + return exynos5_set_i2s_clk_source(i2s_id); + else + return 0; } 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..8002bce 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -220,10 +220,20 @@ 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_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; @@ -463,11 +474,11 @@ static int exynos4_pinmux_config(int peripheral, int flags) int exynos_pinmux_config(int peripheral, int flags) { - if (cpu_is_exynos5()) + if (cpu_is_exynos5()) { return exynos5_pinmux_config(peripheral, flags); - else if (cpu_is_exynos4()) + } else if (cpu_is_exynos4()) { return exynos4_pinmux_config(peripheral, flags); - else { + } else { debug("pinmux functionality not supported\n"); return -1; } diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 71075bd..1d6fa93 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); +int 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..30d1470 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,22 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx) } /* Select Clk Source for Audio1 */ - set_i2s_clk_source(); + ret = set_i2s_clk_source(pi2s_tx->id); + if (ret == -1) { + debug("%s: unsupported clock for i2s-%d\n", __func__, + pi2s_tx->id); + return -1; + } /* Set Prescaler to get MCLK */ - set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, - (pi2s_tx->samplingrate * (pi2s_tx->rfs))); + ret = set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->id); + if (ret == -1) { + debug("%s: unsupported prescalar for i2s-%d\n", __func__, + pi2s_tx->id); + return -1; + } /* Configure I2s format */ ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |