[U-Boot] [PATCH 0/9 V2] EXYNOS5: Add Audio support

This patchset adds the audio support for EXYNOS5. This patchset plays a predefined beep sound.
This patchset is based on the following patches: "[U-Boot] [PATCH 1/7 V4] EXYNOS5: Add pinmux support for SPI" "[U-Boot] [PATCH 4/7 V3] EXYNOS5: Add base address for SPI" "[U-Boot] [PATCH 3/7 V3] EXYNOS: Add clock for SPI"
Changes in V2: - renamed i2s.c to samsung-i2s.c. - made exynos_i2s_config pinmux function static. - corrected the commit message for "Enable sound" patch.
Rajeshwari Shinde (9): SOUND: Add I2S driver SOUND: Add WM8994 codec Sound: Add command for audio playback EXYNOS: Add I2S registers EXYNOS: Add parameters required by I2S EXYNOS: Add pinmux for I2S EXYNOS: Add I2S base address EXYNOS: Add clock for I2S SMDK5250: Enable Sound
Makefile | 1 + arch/arm/cpu/armv7/exynos/clock.c | 119 ++++ arch/arm/cpu/armv7/exynos/pinmux.c | 12 + arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 + arch/arm/include/asm/arch-exynos/cpu.h | 3 + arch/arm/include/asm/arch-exynos/i2s-regs.h | 66 +++ arch/arm/include/asm/arch-exynos/periph.h | 1 + arch/arm/include/asm/arch-exynos/sound.h | 44 ++ common/Makefile | 1 + common/cmd_sound.c | 90 +++ drivers/sound/Makefile | 48 ++ drivers/sound/samsung-i2s.c | 358 ++++++++++++ drivers/sound/sound.c | 220 ++++++++ drivers/sound/wm8994.c | 781 +++++++++++++++++++++++++++ drivers/sound/wm8994.h | 87 +++ drivers/sound/wm8994_registers.h | 299 ++++++++++ include/configs/smdk5250.h | 8 + include/i2s.h | 127 +++++ include/sound.h | 62 +++ 20 files changed, 2359 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/i2s-regs.h create mode 100644 arch/arm/include/asm/arch-exynos/sound.h create mode 100644 common/cmd_sound.c create mode 100644 drivers/sound/Makefile create mode 100644 drivers/sound/samsung-i2s.c create mode 100644 drivers/sound/sound.c create mode 100644 drivers/sound/wm8994.c create mode 100644 drivers/sound/wm8994.h create mode 100644 drivers/sound/wm8994_registers.h create mode 100644 include/i2s.h create mode 100644 include/sound.h

This patch adds driver for I2S interface specific to samsung.
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - renamed i2s.c to samsung-i2s.c. Makefile | 1 + drivers/sound/Makefile | 47 ++++++ drivers/sound/samsung-i2s.c | 358 +++++++++++++++++++++++++++++++++++++++++++ drivers/sound/sound.c | 220 ++++++++++++++++++++++++++ include/i2s.h | 127 +++++++++++++++ include/sound.h | 62 ++++++++ 6 files changed, 815 insertions(+), 0 deletions(-) create mode 100644 drivers/sound/Makefile create mode 100644 drivers/sound/samsung-i2s.c create mode 100644 drivers/sound/sound.c create mode 100644 include/i2s.h create mode 100644 include/sound.h
diff --git a/Makefile b/Makefile index f6471e2..fc929e8e 100644 --- a/Makefile +++ b/Makefile @@ -288,6 +288,7 @@ LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o endif LIBS += drivers/rtc/librtc.o LIBS += drivers/serial/libserial.o +LIBS += drivers/sound/libsound.o ifeq ($(CONFIG_GENERIC_LPC_TPM),y) LIBS += drivers/tpm/libtpm.o endif diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile new file mode 100644 index 0000000..18ad2c9 --- /dev/null +++ b/drivers/sound/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2012 Samsung Electronics +# R. Chandrasekar rcsekar@samsung.com +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libsound.o + +COBJS-$(CONFIG_SOUND) += sound.o +COBJS-$(CONFIG_I2S) += samsung-i2s.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +# diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c new file mode 100644 index 0000000..9485980 --- /dev/null +++ b/drivers/sound/samsung-i2s.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar rcsekar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <asm/arch/clk.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/i2s-regs.h> +#include <asm/io.h> +#include <common.h> +#include <sound.h> +#include <i2s.h> + +#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf) +#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf) +#define FIC_TXCOUNT(x) (((x) >> 8) & 0xf) +#define FIC_RXCOUNT(x) (((x) >> 0) & 0xf) +#define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f) + +#define TIMEOUT_I2S_TX 100 /* i2s transfer timeout */ + +/* + * Sets the frame size for I2S LR clock + * + * @param i2s_reg i2s regiter address + * @param rfs Frame Size + */ +static void i2s_set_lr_framesize(struct i2s_reg *i2s_reg, unsigned int rfs) +{ + unsigned int mod = readl(&i2s_reg->mod); + + mod &= ~MOD_RCLK_MASK; + + switch (rfs) { + case 768: + mod |= MOD_RCLK_768FS; + break; + case 512: + mod |= MOD_RCLK_512FS; + break; + case 384: + mod |= MOD_RCLK_384FS; + break; + default: + mod |= MOD_RCLK_256FS; + break; + } + + writel(mod, &i2s_reg->mod); +} + +/* + * Sets the i2s transfer control + * + * @param i2s_reg i2s regiter address + * @param on 1 enable tx , 0 disable tx transfer + */ +static void i2s_txctrl(struct i2s_reg *i2s_reg, int on) +{ + unsigned int con = readl(&i2s_reg->con); + unsigned int mod = readl(&i2s_reg->mod) & ~MOD_MASK; + + if (on) { + con |= CON_ACTIVE; + con &= ~CON_TXCH_PAUSE; + + } else { + + con |= CON_TXCH_PAUSE; + con &= ~CON_ACTIVE; + } + + writel(mod, &i2s_reg->mod); + writel(con, &i2s_reg->con); +} + +/* + * set the bit clock frame size (in multiples of LRCLK) + * + * @param i2s_reg i2s regiter address + * @param bfs bit Frame Size + */ +static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs) +{ + unsigned int mod = readl(&i2s_reg->mod); + + mod &= ~MOD_BCLK_MASK; + + switch (bfs) { + case 48: + mod |= MOD_BCLK_48FS; + break; + case 32: + mod |= MOD_BCLK_32FS; + break; + case 24: + mod |= MOD_BCLK_24FS; + break; + case 16: + mod |= MOD_BCLK_16FS; + break; + default: + return; + } + writel(mod, &i2s_reg->mod); +} + +/* + * flushes the i2stx fifo + * + * @param i2s_reg i2s regiter address + * @param flush Tx fifo flush command (0x00 - do not flush + * 0x80 - flush tx fifo) + */ +void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush) +{ + /* Flush the FIFO */ + setbits_le32(&i2s_reg->fic, flush); + clrbits_le32(&i2s_reg->fic, flush); +} + +/* + * Set System Clock direction + * + * @param i2s_reg i2s regiter address + * @param dir Clock direction + * + * @return int value 0 for success, -1 in case of error + */ +int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir) +{ + unsigned int mod = readl(&i2s_reg->mod); + + if (dir == SND_SOC_CLOCK_IN) + mod |= MOD_CDCLKCON; + else + mod &= ~MOD_CDCLKCON; + + writel(mod, &i2s_reg->mod); + + return 0; +} + +/* + * Sets I2S Clcok format + * + * @param fmt i2s clock properties + * @param i2s_reg i2s regiter address + * + * @return int value 0 for success, -1 in case of error + */ +int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt) +{ + unsigned int mod = readl(&i2s_reg->mod); + unsigned int tmp = 0; + unsigned int ret = 0; + + /* Format is priority */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + tmp |= MOD_LR_RLOW; + tmp |= MOD_SDF_MSB; + break; + case SND_SOC_DAIFMT_LEFT_J: + tmp |= MOD_LR_RLOW; + tmp |= MOD_SDF_LSB; + break; + case SND_SOC_DAIFMT_I2S: + tmp |= MOD_SDF_IIS; + break; + default: + debug("%s: Invalid format priority [0x%x]\n", __func__, + (fmt & SND_SOC_DAIFMT_FORMAT_MASK)); + return -1; + } + + /* + * INV flag is relative to the FORMAT flag - if set it simply + * flips the polarity specified by the Standard + */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + if (tmp & MOD_LR_RLOW) + tmp &= ~MOD_LR_RLOW; + else + tmp |= MOD_LR_RLOW; + break; + default: + debug("%s: Invalid clock ploarity input [0x%x]\n", __func__, + (fmt & SND_SOC_DAIFMT_INV_MASK)); + return -1; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + tmp |= MOD_SLAVE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* Set default source clock in Master mode */ + ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT); + if (ret != 0) { + debug("%s:set i2s clock direction failed\n", __func__); + return -1; + } + break; + default: + debug("%s: Invalid master selection [0x%x]\n", __func__, + (fmt & SND_SOC_DAIFMT_MASTER_MASK)); + return -1; + } + + mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE); + mod |= tmp; + writel(mod, &i2s_reg->mod); + + return 0; +} + +/* + * Sets the sample width in bits + * + * @param blc samplewidth (size of sample in bits) + * @param i2s_reg i2s regiter address + * + * @return int value 0 for success, -1 in case of error + */ +int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc) +{ + unsigned int mod = readl(&i2s_reg->mod); + + mod &= ~MOD_BLCP_MASK; + mod &= ~MOD_BLC_MASK; + + switch (blc) { + case 8: + mod |= MOD_BLCP_8BIT; + mod |= MOD_BLC_8BIT; + break; + case 16: + mod |= MOD_BLCP_16BIT; + mod |= MOD_BLC_16BIT; + break; + + case 24: + mod |= MOD_BLCP_24BIT; + mod |= MOD_BLC_24BIT; + break; + default: + debug("%s: Invalid sample size input [0x%x]\n", + __func__, blc); + return -1; + } + writel(mod, &i2s_reg->mod); + + return 0; +} + +int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data, + unsigned long data_size) +{ + int i; + int start; + struct i2s_reg *i2s_reg = + (struct i2s_reg *)pi2s_tx->base_address; + + if (data_size < FIFO_LENGTH) { + debug("%s : Invalid data size\n", __func__); + return -1; /* invalid pcm data size */ + } + + /* fill the tx buffer before stating the tx transmit */ + for (i = 0; i < FIFO_LENGTH; i++) + writel(*data++, &i2s_reg->txd); + + data_size -= FIFO_LENGTH; + i2s_txctrl(i2s_reg, I2S_TX_ON); + + while (data_size > 0) { + start = get_timer(0); + if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) { + writel(*data++, &i2s_reg->txd); + data_size--; + } else { + if (get_timer(start) > TIMEOUT_I2S_TX) { + i2s_txctrl(i2s_reg, I2S_TX_OFF); + debug("%s: I2S Transfer Timeout\n", __func__); + return -1; + } + } + } + i2s_txctrl(i2s_reg, I2S_TX_OFF); + + return 0; +} + +int i2s_tx_init(struct i2stx_info *pi2s_tx) +{ + int ret; + struct i2s_reg *i2s_reg = + (struct i2s_reg *)pi2s_tx->base_address; + + /* Initialize GPIO for I2s */ + exynos_pinmux_config(PERIPH_ID_I2S1, 0); + + /* Set EPLL Clock */ + ret = clock_epll_set_rate(pi2s_tx->audio_pll_clk); + if (ret != 0) { + debug("%s: epll clock set rate falied\n", __func__); + return -1; + } + + /* Select Clk Source for Audio1 */ + clock_select_i2s_clk_source(); + + /* Set Prescaler to get MCLK */ + clock_set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk, + (pi2s_tx->samplingrate * (pi2s_tx->rfs))); + + /* Configure I2s format */ + ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + 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); + if (ret != 0) { + debug("%s:set sample rate failed\n", __func__); + return -1; + } + + i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs); + /* disable i2s transfer flag and flush the fifo */ + i2s_txctrl(i2s_reg, I2S_TX_OFF); + i2s_fifo(i2s_reg, FIC_TXFLUSH); + } else + debug("%s: failed\n", __func__); + + return ret; +} diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c new file mode 100644 index 0000000..84a7281 --- /dev/null +++ b/drivers/sound/sound.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar rcsekar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <malloc.h> +#include <common.h> +#include <asm/io.h> +#include <i2c.h> +#include <i2s.h> +#include <sound.h> +#include "wm8994.h" +#include <asm/arch/sound.h> + +/* defines */ +#define SOUND_400_HZ 400 +#define SOUND_BITS_IN_BYTE 8 + +/* pcm values for 400hz 48k sampling rate from 1 cycle */ +unsigned short sine_table_400[120] = { + 0, 1714, 3425, 5125, 6812, 8480, 10125, 11742, 13327, 14875, 16383, + 17846, 19259, 20620, 21925, 23169, 24350, 25464, 26509, 27480, 28377, + 29195, 29934, 30590, 31163, 31650, 32050, 32363, 32587, 32722, 32767, + 32722, 32587, 32363, 32050, 31650, 31163, 30590, 29934, 29195, 28377, + 27480, 26509, 25464, 24350, 23169, 21925, 20620, 19259, 17846, 16383, + 14875, 13327, 11742, 10125, 8480, 6812, 5125, 3425, 1714, 0, -1714, + -3425, -5125, -6812, -8480, -10125, -11742, -13327, -14875, -16383, + -17846, -19259, -20620, -21925, -23169, -24350, -25464, -26509, + -27480, -28377, -29195, -29934, -30590, -31163, -31650, -32050, + -32363, -32587, -32722, -32767, -32722, -32587, -32363, -32050, + -31650, -31163, -30590, -29934, -29195, -28377, -27480, -26509, + -25464, -24350, -23169, -21925, -20620, -19259, -17846, -16383, + -14875, -13327, -11742, -10125, -8480, -6812, -5125, -3425, -1714 +}; + +/* Globals */ +struct i2stx_info g_i2stx_pri; +struct sound_codec_info g_codec_info; + +/* + * get_sound_fdt_values gets fdt values for i2s parameters + * + * @param i2stx_info i2s transmitter transfer param structure + * @param blob FDT blob + */ +static void get_sound_i2s_values(struct i2stx_info *i2s) +{ + i2s->base_address = samsung_get_base_i2s(); + i2s->audio_pll_clk = I2S_PLL_CLK; + i2s->samplingrate = I2S_SAMPLING_RATE; + i2s->bitspersample = I2S_BITS_PER_SAMPLE; + i2s->channels = I2S_CHANNELS; + i2s->rfs = I2S_RFS; + i2s->bfs = I2S_BFS; +} + +/* + * Gets fdt values for wm8994 config parameters + * + * @param pcodec_info codec information structure + * @param blob FDT blob + * @return int value, 0 for success + */ +static int get_sound_wm8994_values(struct sound_codec_info *pcodec_info) +{ + int error = 0; + + switch (AUDIO_COMPAT) { + case AUDIO_COMPAT_SPI: + debug("%s: Support not added for SPI interface\n", __func__); + return -1; + break; + case AUDIO_COMPAT_I2C: + pcodec_info->i2c_bus = AUDIO_I2C_BUS; + pcodec_info->i2c_dev_addr = AUDIO_I2C_REG; + debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); + break; + default: + debug("%s: Unknown compat id %d\n", __func__, AUDIO_COMPAT); + return -1; + } + + if (error == -1) { + debug("fail to get wm8994 codec node properties\n"); + return -1; + } + + return 0; +} + +/* + * Gets fdt values for codec config parameters + * + * @param pcodec_info codec information structure + * @param blob FDT blob + * @return int value, 0 for success + */ +static int get_sound_codec_values(struct sound_codec_info *pcodec_info) +{ + int error = 0; + const char *codectype; + + codectype = AUDIO_CODEC; + + if (!strcmp(codectype, "wm8994")) { + pcodec_info->codec_type = CODEC_WM_8994; + error = get_sound_wm8994_values(pcodec_info); + } else + error = -1; + + if (error == -1) { + debug("fail to get sound codec node properties\n"); + return -1; + } + + return 0; +} + +int sound_init(void) +{ + int ret; + struct i2stx_info *pi2s_tx = &g_i2stx_pri; + struct sound_codec_info *pcodec_info = &g_codec_info; + + /* Get the I2S Values */ + get_sound_i2s_values(pi2s_tx); + + /* Get the codec Values */ + if (get_sound_codec_values(pcodec_info) < 0) + return -1; + + ret = i2s_tx_init(pi2s_tx); + if (ret) { + debug("%s: Failed to init i2c transmit: ret=%d\n", __func__, + ret); + return ret; + } + + /* Check the codec type and initialise the same */ + if (pcodec_info->codec_type == CODEC_WM_8994) { + ret = wm8994_init(pcodec_info, WM8994_AIF2, + pi2s_tx->samplingrate, + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->bitspersample, pi2s_tx->channels); + } else { + debug("%s: Unknown code type %d\n", __func__, + pcodec_info->codec_type); + return -1; + } + if (ret) { + debug("%s: Codec init failed\n", __func__); + return -1; + } + + return ret; +} + +/* + * Generates 400hz sine wave data for 1sec + * + * @param samplingrate samplinng rate of the sinewave need to be generated + * @param data data buffer pointer + */ +static void sound_prepare_sinewave_400hz_buffer(unsigned short *data) +{ + int freq = SOUND_400_HZ; + int i; + + while (freq--) { + i = ARRAY_SIZE(sine_table_400); + + for (i = 0; i < ARRAY_SIZE(sine_table_400); i++) { + *data++ = sine_table_400[i]; + *data++ = sine_table_400[i]; + } + } +} + +int sound_play(void) +{ + unsigned int *data; + unsigned long data_size; + unsigned int ret; + + /* Sine wave Buffer length computation */ + data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels; + data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE); + data = malloc(data_size); + + if (data == NULL) { + debug("%s: malloc failed\n", __func__); + return -1; + } + + sound_prepare_sinewave_400hz_buffer((unsigned short *)data); + + ret = i2s_transfer_tx_data(&g_i2stx_pri, data, + (data_size / sizeof(int))); + free(data); + + return ret; +} diff --git a/include/i2s.h b/include/i2s.h new file mode 100644 index 0000000..f1b642e --- /dev/null +++ b/include/i2s.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar rcsekar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __I2S_H__ +#define __I2S_H__ + +/* + * DAI hardware audio formats. + * + * Describes the physical PCM data formating and clocking. Add new formats + * to the end. + */ +#define SND_SOC_DAIFMT_I2S 1 /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J 2 /* Right Justified mode */ +#define SND_SOC_DAIFMT_LEFT_J 3 /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A 4 /* L data MSB after FRM LRC */ +#define SND_SOC_DAIFMT_DSP_B 5 /* L data MSB during FRM LRC */ +#define SND_SOC_DAIFMT_AC97 6 /* AC97 */ +#define SND_SOC_DAIFMT_PDM 7 /* Pulse density modulation */ + +/* left and right justified also known as MSB and LSB respectively */ +#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J +#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J + +/* + * DAI hardware signal inversions. + * + * Specifies whether the DAI can also support inverted clocks for the specified + * format. + */ +#define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */ +#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */ +#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */ + +/* + * DAI hardware clock masters. + * + * This is wrt the codec, the inverse is true for the interface + * i.e. if the codec is clk and FRM master then the interface is + * clk and frame slave. + */ +#define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */ +#define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */ +#define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */ + +#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 +#define SND_SOC_DAIFMT_INV_MASK 0x0f00 +#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 + +/* + * Master Clock Directions + */ +#define SND_SOC_CLOCK_IN 0 +#define SND_SOC_CLOCK_OUT 1 + +/* I2S Tx Control */ +#define I2S_TX_ON 1 +#define I2S_TX_OFF 0 + +#define FIFO_LENGTH 64 + +/* I2s Registers */ +struct i2s_reg { + unsigned int con; /* base + 0 , Control register */ + unsigned int mod; /* Mode register */ + unsigned int fic; /* FIFO control register */ + unsigned int psr; /* Reserved */ + unsigned int txd; /* Transmit data register */ + unsigned int rxd; /* Receive Data Register */ +}; + +/* This structure stores the i2s related information */ +struct i2stx_info { + unsigned int rfs; /* LR clock frame size */ + unsigned int bfs; /* Bit slock frame size */ + unsigned int audio_pll_clk; /* Audio pll frequency in Hz */ + unsigned int samplingrate; /* sampling rate */ + unsigned int bitspersample; /* bits per sample */ + unsigned int channels; /* audio channels */ + unsigned int base_address; /* I2S Register Base */ +}; + +/* + * Sends the given data through i2s tx + * + * @param pi2s_tx pointer of i2s transmitter parameter structure. + * @param *data address of the data buffer + * @param data_size array size of the int buffer (total size / size of int) + * + * @return int value 0 for success, -1 in case of error + */ +int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data, + unsigned long data_size); + +/* + * Initialise i2s transmiter + * + * @param pi2s_tx pointer of i2s transmitter parameter structure. + * + * @return int value 0 for success, -1 in case of error + */ +int i2s_tx_init(struct i2stx_info *pi2s_tx); + +#endif /* __I2S_H__ */ diff --git a/include/sound.h b/include/sound.h new file mode 100644 index 0000000..1d29ded --- /dev/null +++ b/include/sound.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar < rcsekar@samsung.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __SOUND_H__ +#define __SOUND_H__ + +/* sound codec enum */ +enum en_sound_codec { + CODEC_WM_8994, + CODEC_WM_8995, + CODEC_MAX +}; + +/* sound codec enum */ +enum sound_compat { + AUDIO_COMPAT_SPI, + AUDIO_COMPAT_I2C, +}; + +/* Codec information structure to store the info from device tree */ +struct sound_codec_info { + int i2c_bus; + int i2c_dev_addr; + enum en_sound_codec codec_type; +}; + +/* + * Initialises audio sub system + * + * @return int value 0 for success, -1 for error + */ +int sound_init(void); + +/* + * plays the pcm data buffer in pcm_data.h through i2s1 to make the + * sine wave sound + * + * @return int 0 for success, -1 for error + */ +int sound_play(void); + +#endif /* __SOUND__H__ */

Hi,
On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds driver for I2S interface specific to samsung.
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Changes in V2:
- renamed i2s.c to samsung-i2s.c.
Makefile | 1 + drivers/sound/Makefile | 47 ++++++ drivers/sound/samsung-i2s.c | 358 +++++++++++++++++++++++++++++++++++++++++++ drivers/sound/sound.c | 220 ++++++++++++++++++++++++++ include/i2s.h | 127 +++++++++++++++ include/sound.h | 62 ++++++++ 6 files changed, 815 insertions(+), 0 deletions(-) create mode 100644 drivers/sound/Makefile create mode 100644 drivers/sound/samsung-i2s.c create mode 100644 drivers/sound/sound.c create mode 100644 include/i2s.h create mode 100644 include/sound.h
Rather than have a big table for the sound, can we calculate it, as in the Chromium tree?
Regards, Simon
while (freq--) {
i = ARRAY_SIZE(sine_table_400);
for (i = 0; i < ARRAY_SIZE(sine_table_400); i++) {
*data++ = sine_table_400[i];
*data++ = sine_table_400[i];
}
}
+}

This pastc adds driver for audio codec WM8994
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - None drivers/sound/Makefile | 1 + drivers/sound/wm8994.c | 781 ++++++++++++++++++++++++++++++++++++++ drivers/sound/wm8994.h | 87 +++++ drivers/sound/wm8994_registers.h | 299 +++++++++++++++ 4 files changed, 1168 insertions(+), 0 deletions(-) create mode 100644 drivers/sound/wm8994.c create mode 100644 drivers/sound/wm8994.h create mode 100644 drivers/sound/wm8994_registers.h
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 18ad2c9..8fdffb1 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libsound.o
COBJS-$(CONFIG_SOUND) += sound.o COBJS-$(CONFIG_I2S) += samsung-i2s.o +COBJS-$(CONFIG_SOUND_WM8994) += wm8994.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c new file mode 100644 index 0000000..21604f1 --- /dev/null +++ b/drivers/sound/wm8994.c @@ -0,0 +1,781 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar rcsekar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#define DEBUG +#include <asm/arch/clk.h> +#include <asm/arch/cpu.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <common.h> +#include <div64.h> +#include <i2c.h> +#include <i2s.h> +#include <sound.h> +#include "wm8994.h" +#include "wm8994_registers.h" + +/* defines for wm8994 system clock selection */ +#define SEL_MCLK1 0x00 +#define SEL_MCLK2 0x08 +#define SEL_FLL1 0x10 +#define SEL_FLL2 0x18 + +/* fll config to configure fll */ +struct wm8994_fll_config { + int src; /* Source */ + int in; /* Input frequency in Hz */ + int out; /* output frequency in Hz */ +}; + +/* codec private data */ +struct wm8994_priv { + enum wm8994_type type; /* codec type of wolfson */ + int revision; /* Revision */ + int sysclk[WM8994_MAX_AIF]; /* System clock freqency in Hz */ + int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */ + int aifclk[WM8994_MAX_AIF]; /* audio interfce clock in Hz */ + struct wm8994_fll_config fll[2]; /* fll config to configure fll */ +}; + +/* wm 8994 supported sampling rate vlaues */ +static unsigned int src_rate[] = { + 8000, 11025, 12000, 16000, 22050, 24000, + 32000, 44100, 48000, 88200, 96000 +}; + +/* op clock divisions */ +static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; + +/* lr clock framsize ratio */ +static int fs_ratios[] = { + 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 +}; + +/* bit clock divisions */ +static int bclk_divs[] = { + 10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480, + 640, 880, 960, 1280, 1760, 1920 +}; + +/* Global */ +struct wm8994_priv g_wm8994_info; +unsigned int g_wm8994_i2c_dev_addr; + +/* + * Initialise I2C for wm 8994 + * + * @param bus no i2c bus number in which wm8994 is connected + */ +static void wm8994_i2c_init(int bus_no) +{ + i2c_set_bus_num(bus_no); +} + +/* + * Writes value to a device register through i2c + * + * @param reg reg number to be write + * @param data data to be writen to the above registor + * + * @return int value 1 for change, 0 for no change or negative error code. + */ +static int wm8994_i2c_write(unsigned int reg, unsigned short data) +{ + unsigned char val[2]; + + val[0] = (unsigned char)((data >> 8) & 0xff); + val[1] = (unsigned char)(data & 0xff); + debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data); + + return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2); +} + +/* + * Read a value from a device register through i2c + * + * @param reg reg number to be read + * @param data address of read data to be stored + * + * @return int value 0 for success, -1 in case of error. + */ +static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data) +{ + unsigned char val[2]; + int ret; + + ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2); + if (ret != 0) { + debug("%s: Error while reading register %#04x\n", + __func__, reg); + return -1; + } + *data = val[0]; + *data <<= 8; + *data |= val[1]; + + return 0; +} + +/* + * update device register bits through i2c + * + * @param reg codec register + * @param mask register mask + * @param value new value + * + * @return int value 1 for change, 0 for no change or negative error code. + */ +static int wm8994_update_bits(unsigned int reg, unsigned short mask, + unsigned short value) +{ + int change , ret = 0; + unsigned short old, new; + + if (wm8994_i2c_read(reg, &old) != 0) + return -1; + new = (old & ~mask) | (value & mask); + change = (old != new) ? 1 : 0; + if (change) + ret = wm8994_i2c_write(reg, new); + if (ret < 0) + return ret; + + return change; +} + +/* + * Sets i2s set format + * + * @param aif_id Interface ID + * @param fmt i2S format + * + * @return -1 for error and 0 Success. + */ +int wm8994_set_fmt(int aif_id, unsigned int fmt) +{ + int ms_reg; + int aif_reg; + int ms = 0; + int aif = 0; + int aif_clk = 0; + int error = 0; + + switch (aif_id) { + case 1: + ms_reg = WM8994_AIF1_MASTER_SLAVE; + aif_reg = WM8994_AIF1_CONTROL_1; + aif_clk = WM8994_AIF1_CLOCKING_1; + break; + case 2: + ms_reg = WM8994_AIF2_MASTER_SLAVE; + aif_reg = WM8994_AIF2_CONTROL_1; + aif_clk = WM8994_AIF2_CLOCKING_1; + break; + default: + debug("%s: Invalid audio interface selection\n", __func__); + return -1; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBM_CFM: + ms = WM8994_AIF1_MSTR; + break; + default: + debug("%s: Invalid i2s master selection\n", __func__); + return -1; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif |= WM8994_AIF1_LRCLK_INV; + case SND_SOC_DAIFMT_DSP_A: + aif |= 0x18; + break; + case SND_SOC_DAIFMT_I2S: + aif |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif |= 0x8; + break; + default: + debug("%s: Invalid i2s format selection\n", __func__); + return -1; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif |= WM8994_AIF1_BCLK_INV; + break; + default: + debug("%s: Invalid i2s frame inverse selection\n", + __func__); + return -1; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aif |= WM8994_AIF1_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif |= WM8994_AIF1_LRCLK_INV; + break; + default: + debug("%s: Invalid i2s clock polarity selection\n", + __func__); + return -1; + } + break; + default: + debug("%s: Invalid i2s format selection\n", __func__); + return -1; + } + + error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV | + WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif); + + error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms); + error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK, + WM8994_AIF1CLK_ENA); + if (error < 0) { + debug("%s: codec register access error\n", __func__); + return -1; + } + + return 0; +} + +/* + * Sets hw params FOR WM8994 + * + * @param sampling_rate Sampling rate + * @param bits_per_sample Bits per sample + * @param Channels Channels in the given audio input + * + * @return -1 for error and 0 Success. + */ +static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id, + unsigned int sampling_rate, unsigned int bits_per_sample, + unsigned int channels) +{ + int aif1_reg; + int aif2_reg; + int bclk_reg; + int bclk = 0; + int rate_reg; + int aif1 = 0; + int aif2 = 0; + int rate_val = 0; + int id = aif_id - 1; + int i, cur_val, best_val, bclk_rate, best; + unsigned short reg_data; + int ret = 0; + + switch (aif_id) { + case 1: + aif1_reg = WM8994_AIF1_CONTROL_1; + aif2_reg = WM8994_AIF1_CONTROL_2; + bclk_reg = WM8994_AIF1_BCLK; + rate_reg = WM8994_AIF1_RATE; + break; + case 2: + aif1_reg = WM8994_AIF2_CONTROL_1; + aif2_reg = WM8994_AIF2_CONTROL_2; + bclk_reg = WM8994_AIF2_BCLK; + rate_reg = WM8994_AIF2_RATE; + break; + default: + return -1; + } + + bclk_rate = sampling_rate * 32; + switch (bits_per_sample) { + case 16: + bclk_rate *= 16; + break; + case 20: + bclk_rate *= 20; + aif1 |= 0x20; + break; + case 24: + bclk_rate *= 24; + aif1 |= 0x40; + break; + case 32: + bclk_rate *= 32; + aif1 |= 0x60; + break; + default: + return -1; + } + + /* Try to find an appropriate sample rate; look for an exact match. */ + for (i = 0; i < ARRAY_SIZE(src_rate); i++) + if (src_rate[i] == sampling_rate) + break; + + if (i == ARRAY_SIZE(src_rate)) { + debug("%s: Could not get the best matching samplingrate\n", + __func__); + return -1; + } + + rate_val |= i << WM8994_AIF1_SR_SHIFT; + + /* AIFCLK/fs ratio; look for a close match in either direction */ + best = 0; + best_val = abs((fs_ratios[0] * sampling_rate) + - wm8994->aifclk[id]); + + for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) { + cur_val = abs((fs_ratios[i] * sampling_rate) + - wm8994->aifclk[id]); + if (cur_val >= best_val) + continue; + best = i; + best_val = cur_val; + } + + rate_val |= best; + + /* + * We may not get quite the right frequency if using + * approximate clocks so look for the closest match that is + * higher than the target (we need to ensure that there enough + * BCLKs to clock out the samples). + */ + best = 0; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate; + if (cur_val < 0) /* BCLK table is sorted */ + break; + best = i; + } + + if (i == ARRAY_SIZE(bclk_divs)) { + debug("%s: Could not get the best matching bclk division\n", + __func__); + return -1; + } + + bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best]; + bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; + + if (wm8994_i2c_read(aif1_reg, ®_data) != 0) + return -1; + + if ((channels == 1) && ((reg_data & 0x18) == 0x18)) + aif2 |= WM8994_AIF1_MONO; + + if (wm8994->aifclk[id] == 0) + return -1; + + ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1); + ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2); + ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk); + ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK | + WM8994_AIF1CLK_RATE_MASK, rate_val); + + debug("rate vale = %x , bclk val= %x\n", rate_val, bclk); + + if (ret < 0) { + debug("%s: codec register access error\n", __func__); + return -1; + } + + return 0; +} + +/* + * Configures Audio interface Clock + * + * @param wm8994 wm8994 information pointer + * @param aif Audio Interface ID + * + * @return -1 for error and 0 Success. + */ +static int configure_aif_clock(struct wm8994_priv *wm8994, int aif) +{ + int rate; + int reg1 = 0; + int offset; + int ret; + + if (aif) + offset = 4; + else + offset = 0; + + switch (wm8994->sysclk[aif]) { + case WM8994_SYSCLK_MCLK1: + reg1 |= SEL_MCLK1; + rate = wm8994->mclk[0]; + break; + + case WM8994_SYSCLK_MCLK2: + reg1 |= SEL_MCLK2; + rate = wm8994->mclk[1]; + break; + + case WM8994_SYSCLK_FLL1: + reg1 |= SEL_FLL1; + rate = wm8994->fll[0].out; + break; + + case WM8994_SYSCLK_FLL2: + reg1 |= SEL_FLL2; + rate = wm8994->fll[1].out; + break; + + default: + debug("%s: Invalid input clock selection [%d]\n", + __func__, wm8994->sysclk[aif]); + return -1; + } + + /* if input clock frequenct is more than 135Mhz then divide */ + if (rate >= WM8994_MAX_INPUT_CLK_FREQ) { + rate /= 2; + reg1 |= WM8994_AIF1CLK_DIV; + } + + wm8994->aifclk[aif] = 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, + WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK | + WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC | + WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); + + if (ret < 0) { + debug("%s: codec register access error\n", __func__); + return -1; + } + + return 0; +} + +/* + * Configures Audio interface for the given frequency + * + * @param wm8994 wm8994 information + * @param aif_id Audio Interface + * @param clk_id Input Clock ID + * @param freq Sampling frequency in Hz + * + * @return -1 for error and 0 success. + */ +static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id, + int clk_id, unsigned int freq) +{ + int i; + int ret = 0; + + wm8994->sysclk[aif_id - 1] = clk_id; + + switch (clk_id) { + case WM8994_SYSCLK_MCLK1: + wm8994->mclk[0] = freq; + if (aif_id == 2) { + ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 , + WM8994_AIF2DAC_DIV_MASK , 0); + } + break; + + case WM8994_SYSCLK_MCLK2: + /* TODO: Set GPIO AF */ + wm8994->mclk[1] = freq; + break; + + case WM8994_SYSCLK_FLL1: + case WM8994_SYSCLK_FLL2: + break; + + case WM8994_SYSCLK_OPCLK: + /* Special case - a division (times 10) is given and + * no effect on main clocking. + */ + if (freq) { + for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) + if (opclk_divs[i] == freq) + break; + if (i == ARRAY_SIZE(opclk_divs)) + return -1; + ret = wm8994_update_bits(WM8994_CLOCKING_2, + WM8994_OPCLK_DIV_MASK, i); + ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2, + WM8994_OPCLK_ENA, WM8994_OPCLK_ENA); + } else { + ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2, + WM8994_OPCLK_ENA, 0); + } + + default: + debug("%s Invalid input clock selection [%d]\n", + __func__, clk_id); + return -1; + } + + ret |= configure_aif_clock(wm8994, aif_id - 1); + + if (ret < 0) { + debug("%s: codec register access error\n", __func__); + return -1; + } + + return 0; +} + +/* + * Initializes Volume for AIF2 to HP path + * + * @returns -1 for error and 0 Success. + * + */ +static int wm8994_init_volume_aif2_dac1(void) +{ + int ret; + + /* Unmute AIF2DAC */ + ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1, + WM8994_AIF2DAC_MUTE_MASK, 0); + + + ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME, + WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK, + WM8994_AIF2DAC_VU | 0xff); + + ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME, + WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK, + WM8994_AIF2DAC_VU | 0xff); + + + 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) +{ + const char *devname; + unsigned short reg_data; + int ret; + + wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */ + + ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, ®_data); + if (ret < 0) { + debug("Failed to read ID register\n"); + goto err; + } + + if (reg_data == WM8994_ID) { + devname = "WM8994"; + debug("Device registered as type %d\n", wm8994->type); + wm8994->type = WM8994; + } else { + debug("Device is not a WM8994, ID is %x\n", ret); + ret = -1; + goto err; + } + + ret = wm8994_i2c_read(WM8994_CHIP_REVISION, ®_data); + if (ret < 0) { + debug("Failed to read revision register: %d\n", ret); + goto err; + } + wm8994->revision = reg_data; + debug("%s revision %c\n", devname, 'A' + wm8994->revision); + + /* VMID Selection */ + ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3); + + /* Charge Pump Enable */ + ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK, + WM8994_CP_ENA); + + /* Head Phone Power Enable */ + ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1, + WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA); + + 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); + + /* Head Phone Initialisation */ + ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1, + WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK, + WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY); + + ret |= wm8994_update_bits(WM8994_DC_SERVO_1, + WM8994_DCS_ENA_CHAN_0_MASK | + WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 | + WM8994_DCS_ENA_CHAN_1); + + ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1, + WM8994_HPOUT1L_DLY_MASK | + WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK | + WM8994_HPOUT1R_OUTP_MASK | + WM8994_HPOUT1L_RMV_SHORT_MASK | + WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY | + WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP | + WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT | + WM8994_HPOUT1R_RMV_SHORT); + + /* MIXER Config DAC1 to HP */ + ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1, + WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L); + + 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 (ret < 0) + goto err; + + debug("%s: Codec chip init ok\n", __func__); + return 0; +err: + debug("%s: Codec chip init error\n", __func__); + return -1; +} + +/*wm8994 Device Initialisation */ +int wm8994_init(struct sound_codec_info *pcodec_info, + enum en_audio_interface aif_id, + int sampling_rate, int mclk_freq, + int bits_per_sample, unsigned int channels) +{ + int ret = 0; + + /* shift the device address by 1 for 7 bit addressing */ + g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1; + wm8994_i2c_init(pcodec_info->i2c_bus); + + if (pcodec_info->codec_type == CODEC_WM_8994) + g_wm8994_info.type = WM8994; + else { + debug("%s: Codec id [%d] not defined\n", __func__, + pcodec_info->codec_type); + return -1; + } + + ret = wm8994_device_init(&g_wm8994_info); + if (ret < 0) { + debug("%s: wm8994 codec chip init failed\n", __func__); + return ret; + } + + ret = wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1, + mclk_freq); + if (ret < 0) { + debug("%s: wm8994 codec set sys clock failed\n", __func__); + return ret; + } + + ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate, + bits_per_sample, channels); + + if (ret == 0) { + ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + } + return ret; +} diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h new file mode 100644 index 0000000..3c12cbb --- /dev/null +++ b/drivers/sound/wm8994.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chadrasekar rcsekar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __WM8994_H__ +#define __WM8994_H__ + +/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ +#define WM8994_SYSCLK_MCLK1 1 +#define WM8994_SYSCLK_MCLK2 2 +#define WM8994_SYSCLK_FLL1 3 +#define WM8994_SYSCLK_FLL2 4 + +/* Avilable audi interface ports in wm8994 codec */ +enum en_audio_interface { + WM8994_AIF1 = 1, + WM8994_AIF2, + WM8994_AIF3 +}; + +/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ +#define WM8994_SYSCLK_OPCLK 5 + +#define WM8994_FLL1 1 +#define WM8994_FLL2 2 + +#define WM8994_FLL_SRC_MCLK1 1 +#define WM8994_FLL_SRC_MCLK2 2 +#define WM8994_FLL_SRC_LRCLK 3 +#define WM8994_FLL_SRC_BCLK 4 + +/* maximum available digital interfac in the dac to configure */ +#define WM8994_MAX_AIF 2 + +#define WM8994_MAX_INPUT_CLK_FREQ 13500000 +#define WM8994_ID 0x8994 + +enum wm8994_vmid_mode { + WM8994_VMID_NORMAL, + WM8994_VMID_FORCE, +}; + +/* wm 8994 family devices */ +enum wm8994_type { + WM8994 = 0, + WM8958 = 1, + WM1811 = 2, +}; + +/* + * intialise wm8994 sound codec device for the given configuration + * + * @param pcodec_info pointer value of the sound codec info structure + * parsed from device tree + * @param aif_id enum value of codec interface port in which + * soc i2s is connected + * @param sampling_rate Sampling rate + * @param mclk_freq MCLK Frequency + * @param bits_per_sample bits per Sample + * @param channels Number of channnels + * + * @returns -1 for error and 0 Success. + */ +int wm8994_init(struct sound_codec_info *pcodec_info, + enum en_audio_interface aif_id, + int sampling_rate, int mclk_freq, + int bits_per_sample, unsigned int channels); +#endif /*__WM8994_H__ */ diff --git a/drivers/sound/wm8994_registers.h b/drivers/sound/wm8994_registers.h new file mode 100644 index 0000000..dacf6b6 --- /dev/null +++ b/drivers/sound/wm8994_registers.h @@ -0,0 +1,299 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_REGISTERS_H__ +#define __MFD_WM8994_REGISTERS_H__ + +/* + * Register values. + */ +#define WM8994_SOFTWARE_RESET 0x00 +#define WM8994_POWER_MANAGEMENT_1 0x01 +#define WM8994_POWER_MANAGEMENT_2 0x02 +#define WM8994_POWER_MANAGEMENT_5 0x05 +#define WM8994_LEFT_OUTPUT_VOLUME 0x1C +#define WM8994_RIGHT_OUTPUT_VOLUME 0x1D +#define WM8994_OUTPUT_MIXER_1 0x2D +#define WM8994_OUTPUT_MIXER_2 0x2E +#define WM8994_CHARGE_PUMP_1 0x4C +#define WM8994_DC_SERVO_1 0x54 +#define WM8994_ANALOGUE_HP_1 0x60 +#define WM8994_CHIP_REVISION 0x100 +#define WM8994_AIF1_CLOCKING_1 0x200 +#define WM8994_AIF1_CLOCKING_2 0x201 +#define WM8994_AIF2_CLOCKING_1 0x204 +#define WM8994_CLOCKING_1 0x208 +#define WM8994_CLOCKING_2 0x209 +#define WM8994_AIF1_RATE 0x210 +#define WM8994_AIF2_RATE 0x211 +#define WM8994_RATE_STATUS 0x212 +#define WM8994_AIF1_CONTROL_1 0x300 +#define WM8994_AIF1_CONTROL_2 0x301 +#define WM8994_AIF1_MASTER_SLAVE 0x302 +#define WM8994_AIF1_BCLK 0x303 +#define WM8994_AIF2_CONTROL_1 0x310 +#define WM8994_AIF2_CONTROL_2 0x311 +#define WM8994_AIF2_MASTER_SLAVE 0x312 +#define WM8994_AIF2_BCLK 0x313 +#define WM8994_AIF2_DAC_LEFT_VOLUME 0x502 +#define WM8994_AIF2_DAC_RIGHT_VOLUME 0x503 +#define WM8994_AIF2_DAC_FILTERS_1 0x520 +#define WM8994_DAC1_LEFT_MIXER_ROUTING 0x601 +#define WM8994_DAC1_RIGHT_MIXER_ROUTING 0x602 +#define WM8994_DAC1_LEFT_VOLUME 0x610 +#define WM8994_DAC1_RIGHT_VOLUME 0x611 +#define WM8994_GPIO_3 0x702 +#define WM8994_GPIO_4 0x703 +#define WM8994_GPIO_5 0x704 + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Software Reset + */ +/* SW_RESET */ +#define WM8994_SW_RESET 1 +/* + * R1 (0x01) - Power Management (1) + */ +/* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA 0x0200 +/* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA_MASK 0x0200 +/* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA 0x0100 +/* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA_MASK 0x0100 +/* VMID_SEL - [2:1] */ +#define WM8994_VMID_SEL_MASK 0x0006 +/* BIAS_ENA */ +#define WM8994_BIAS_ENA 0x0001 +/* BIAS_ENA */ +#define WM8994_BIAS_ENA_MASK 0x0001 + +/* + * R2 (0x02) - Power Management (2) + */ +/* OPCLK_ENA */ +#define WM8994_OPCLK_ENA 0x0800 + +/* + * R5 (0x05) - Power Management (5) + */ +/* AIF2DACL_ENA */ +#define WM8994_AIF2DACL_ENA 0x2000 +#define WM8994_AIF2DACL_ENA_MASK 0x2000 +/* AIF2DACR_ENA */ +#define WM8994_AIF2DACR_ENA 0x1000 +#define WM8994_AIF2DACR_ENA_MASK 0x1000 +/* DAC1L_ENA */ +#define WM8994_DAC1L_ENA 0x0002 +#define WM8994_DAC1L_ENA_MASK 0x0002 +/* DAC1R_ENA */ +#define WM8994_DAC1R_ENA 0x0001 +#define WM8994_DAC1R_ENA_MASK 0x0001 + +/* + * R45 (0x2D) - Output Mixer (1) + */ +/* DAC1L_TO_HPOUT1L */ +#define WM8994_DAC1L_TO_HPOUT1L 0x0100 +#define WM8994_DAC1L_TO_HPOUT1L_MASK 0x0100 + +/* + * R46 (0x2E) - Output Mixer (2) + */ +/* DAC1R_TO_HPOUT1R */ +#define WM8994_DAC1R_TO_HPOUT1R 0x0100 +#define WM8994_DAC1R_TO_HPOUT1R_MASK 0x0100 + +/* + * R76 (0x4C) - Charge Pump (1) + */ +/* CP_ENA */ +#define WM8994_CP_ENA 0x8000 +#define WM8994_CP_ENA_MASK 0x8000 +/* + * R84 (0x54) - DC Servo (1) + */ +/* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_1 0x0002 +#define WM8994_DCS_ENA_CHAN_1_MASK 0x0002 +/* DCS_ENA_CHAN_0 */ +#define WM8994_DCS_ENA_CHAN_0 0x0001 +#define WM8994_DCS_ENA_CHAN_0_MASK 0x0001 + +/* + * R96 (0x60) - Analogue HP (1) + */ +/* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_RMV_SHORT 0x0080 +#define WM8994_HPOUT1L_RMV_SHORT_MASK 0x0080 +/* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_OUTP 0x0040 +#define WM8994_HPOUT1L_OUTP_MASK 0x0040 +/* HPOUT1L_DLY */ +#define WM8994_HPOUT1L_DLY 0x0020 +#define WM8994_HPOUT1L_DLY_MASK 0x0020 +/* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_RMV_SHORT 0x0008 +#define WM8994_HPOUT1R_RMV_SHORT_MASK 0x0008 +/* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_OUTP 0x0004 +#define WM8994_HPOUT1R_OUTP_MASK 0x0004 +/* HPOUT1R_DLY */ +#define WM8994_HPOUT1R_DLY 0x0002 +#define WM8994_HPOUT1R_DLY_MASK 0x0002 + +/* + * R512 (0x200) - AIF1 Clocking (1) + */ +/* AIF1CLK_SRC - [4:3] */ +#define WM8994_AIF1CLK_SRC_MASK 0x0018 +/* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_DIV 0x0002 +/* AIF1CLK_ENA */ +#define WM8994_AIF1CLK_ENA 0x0001 +#define WM8994_AIF1CLK_ENA_MASK 0x0001 + +/* + * R517 (0x205) - AIF2 Clocking (2) + */ +/* AIF2DAC_DIV - [5:3] */ +#define WM8994_AIF2DAC_DIV_MASK 0x0038 + +/* + * R520 (0x208) - Clocking (1) + */ +/* AIF2DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA 0x0004 +#define WM8994_AIF2DSPCLK_ENA_MASK 0x0004 +/* SYSDSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA 0x0002 +#define WM8994_SYSDSPCLK_ENA_MASK 0x0002 +/* SYSCLK_SRC */ +#define WM8994_SYSCLK_SRC 0x0001 + +/* + * R521 (0x209) - Clocking (2) + */ +/* OPCLK_DIV - [2:0] */ +#define WM8994_OPCLK_DIV_MASK 0x0007 + +/* + * R528 (0x210) - AIF1 Rate + */ +/* AIF1_SR - [7:4] */ +#define WM8994_AIF1_SR_MASK 0x00F0 +#define WM8994_AIF1_SR_SHIFT 4 +/* AIF1CLK_RATE - [3:0] */ +#define WM8994_AIF1CLK_RATE_MASK 0x000F + +/* + * R768 (0x300) - AIF1 Control (1) + */ +/* AIF1_BCLK_INV */ +#define WM8994_AIF1_BCLK_INV 0x0100 +/* AIF1_LRCLK_INV */ +#define WM8994_AIF1_LRCLK_INV 0x0080 +#define WM8994_AIF1_LRCLK_INV_MASK 0x0080 +/* AIF1_WL - [6:5] */ +#define WM8994_AIF1_WL_MASK 0x0060 +/* AIF1_FMT - [4:3] */ +#define WM8994_AIF1_FMT_MASK 0x0018 + +/* + * R769 (0x301) - AIF1 Control (2) + */ +/* AIF1_MONO */ +#define WM8994_AIF1_MONO 0x0100 + +/* + * R770 (0x302) - AIF1 Master/Slave + */ +/* AIF1_MSTR */ +#define WM8994_AIF1_MSTR 0x4000 +#define WM8994_AIF1_MSTR_MASK 0x4000 + +/* + * R771 (0x303) - AIF1 BCLK + */ +/* AIF1_BCLK_DIV - [8:4] */ +#define WM8994_AIF1_BCLK_DIV_MASK 0x01F0 +#define WM8994_AIF1_BCLK_DIV_SHIFT 4 + +/* + * R1282 (0x502) - AIF2 DAC Left Volume + */ +/* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU 0x0100 +#define WM8994_AIF2DAC_VU_MASK 0x0100 +/* AIF2DACL_VOL - [7:0] */ +#define WM8994_AIF2DACL_VOL_MASK 0x00FF + +/* + * R1283 (0x503) - AIF2 DAC Right Volume + */ +/* AIF2DACR_VOL - [7:0] */ +#define WM8994_AIF2DACR_VOL_MASK 0x00FF + +/* + * R1312 (0x520) - AIF2 DAC Filters (1) + */ +/* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MUTE_MASK 0x0200 + +/* + * R1537 (0x601) - DAC1 Left Mixer Routing + */ +/* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L 0x0004 +#define WM8994_AIF2DACL_TO_DAC1L_MASK 0x0004 + +/* + * R1538 (0x602) - DAC1 Right Mixer Routing + */ +/* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R 0x0004 +#define WM8994_AIF2DACR_TO_DAC1R_MASK 0x0004 + +/* + * R1552 (0x610) - DAC1 Left Volume + */ +/* DAC1L_MUTE */ +#define WM8994_DAC1L_MUTE_MASK 0x0200 +/* DAC1_VU */ +#define WM8994_DAC1_VU 0x0100 +#define WM8994_DAC1_VU_MASK 0x0100 +/* DAC1L_VOL - [7:0] */ +#define WM8994_DAC1L_VOL_MASK 0x00FF + +/* + * R1553 (0x611) - DAC1 Right Volume + */ +/* DAC1R_MUTE */ +#define WM8994_DAC1R_MUTE_MASK 0x0200 +/* DAC1R_VOL - [7:0] */ +#define WM8994_DAC1R_VOL_MASK 0x00FF + +/* + * GPIO + */ +/* OUTPUT PIN */ +#define WM8994_GPIO_DIR_OUTPUT 0x8000 +/* GPIO PIN MASK */ +#define WM8994_GPIO_DIR_MASK 0xFFE0 +/* I2S CLK */ +#define WM8994_GPIO_FUNCTION_I2S_CLK 0x0000 +/* GPn FN */ +#define WM8994_GPIO_FUNCTION_MASK 0x001F +#endif

Hi Rajeshwari,
On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This pastc adds driver for audio codec WM8994
patch
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Changes in V2:
- None
drivers/sound/Makefile | 1 + drivers/sound/wm8994.c | 781 ++++++++++++++++++++++++++++++++++++++ drivers/sound/wm8994.h | 87 +++++ drivers/sound/wm8994_registers.h | 299 +++++++++++++++ 4 files changed, 1168 insertions(+), 0 deletions(-) create mode 100644 drivers/sound/wm8994.c create mode 100644 drivers/sound/wm8994.h create mode 100644 drivers/sound/wm8994_registers.h
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 18ad2c9..8fdffb1 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libsound.o
COBJS-$(CONFIG_SOUND) += sound.o COBJS-$(CONFIG_I2S) += samsung-i2s.o +COBJS-$(CONFIG_SOUND_WM8994) += wm8994.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c new file mode 100644 index 0000000..21604f1 --- /dev/null +++ b/drivers/sound/wm8994.c @@ -0,0 +1,781 @@ +/*
- Copyright (C) 2012 Samsung Electronics
- R. Chandrasekar rcsekar@samsung.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#define DEBUG
can remove this?
+#include <asm/arch/clk.h> +#include <asm/arch/cpu.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <common.h> +#include <div64.h> +#include <i2c.h> +#include <i2s.h> +#include <sound.h>
blank line here maybe?
+#include "wm8994.h" +#include "wm8994_registers.h"
+/* defines for wm8994 system clock selection */ +#define SEL_MCLK1 0x00 +#define SEL_MCLK2 0x08 +#define SEL_FLL1 0x10 +#define SEL_FLL2 0x18
+/* fll config to configure fll */
What is FLL?
+struct wm8994_fll_config {
int src; /* Source */
int in; /* Input frequency in Hz */
int out; /* output frequency in Hz */
+};
+/* codec private data */ +struct wm8994_priv {
enum wm8994_type type; /* codec type of wolfson */
int revision; /* Revision */
int sysclk[WM8994_MAX_AIF]; /* System clock freqency in Hz */
frequency
int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */
int aifclk[WM8994_MAX_AIF]; /* audio interfce clock in Hz */
interface
struct wm8994_fll_config fll[2]; /* fll config to configure fll */
+};
+/* wm 8994 supported sampling rate vlaues */
values
+static unsigned int src_rate[] = {
8000, 11025, 12000, 16000, 22050, 24000,
32000, 44100, 48000, 88200, 96000
+};
+/* op clock divisions */ +static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
+/* lr clock framsize ratio */
frame size?
+static int fs_ratios[] = {
64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
+};
+/* bit clock divisions */
Are these divisors or divisions?
+static int bclk_divs[] = {
10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480,
640, 880, 960, 1280, 1760, 1920
+};
+/* Global */ +struct wm8994_priv g_wm8994_info; +unsigned int g_wm8994_i2c_dev_addr;
Can these be static?
+/*
- Initialise I2C for wm 8994
- @param bus no i2c bus number in which wm8994 is connected
- */
+static void wm8994_i2c_init(int bus_no) +{
i2c_set_bus_num(bus_no);
+}
+/*
- Writes value to a device register through i2c
- @param reg reg number to be write
- @param data data to be writen to the above registor
- @return int value 1 for change, 0 for no change or negative error code.
- */
+static int wm8994_i2c_write(unsigned int reg, unsigned short data) +{
unsigned char val[2];
val[0] = (unsigned char)((data >> 8) & 0xff);
val[1] = (unsigned char)(data & 0xff);
debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data);
return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+}
+/*
- Read a value from a device register through i2c
- @param reg reg number to be read
- @param data address of read data to be stored
- @return int value 0 for success, -1 in case of error.
- */
+static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data) +{
unsigned char val[2];
int ret;
ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
if (ret != 0) {
debug("%s: Error while reading register %#04x\n",
__func__, reg);
return -1;
}
*data = val[0];
*data <<= 8;
*data |= val[1];
Can you do something like:
*data = get_unaligned_le16(val);
return 0;
+}
+/*
- update device register bits through i2c
- @param reg codec register
- @param mask register mask
- @param value new value
- @return int value 1 for change, 0 for no change or negative error code.
Would be clearer if you said "1 if the register value was actually changed"
- */
+static int wm8994_update_bits(unsigned int reg, unsigned short mask,
unsigned short value)
+{
int change , ret = 0;
unsigned short old, new;
if (wm8994_i2c_read(reg, &old) != 0)
return -1;
new = (old & ~mask) | (value & mask);
change = (old != new) ? 1 : 0;
if (change)
ret = wm8994_i2c_write(reg, new);
if (ret < 0)
return ret;
return change;
+}
+/*
- Sets i2s set format
- @param aif_id Interface ID
- @param fmt i2S format
- @return -1 for error and 0 Success.
- */
+int wm8994_set_fmt(int aif_id, unsigned int fmt) +{
int ms_reg;
int aif_reg;
int ms = 0;
int aif = 0;
int aif_clk = 0;
int error = 0;
switch (aif_id) {
case 1:
ms_reg = WM8994_AIF1_MASTER_SLAVE;
aif_reg = WM8994_AIF1_CONTROL_1;
aif_clk = WM8994_AIF1_CLOCKING_1;
break;
case 2:
ms_reg = WM8994_AIF2_MASTER_SLAVE;
aif_reg = WM8994_AIF2_CONTROL_1;
aif_clk = WM8994_AIF2_CLOCKING_1;
break;
default:
debug("%s: Invalid audio interface selection\n", __func__);
return -1;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
break;
case SND_SOC_DAIFMT_CBM_CFM:
ms = WM8994_AIF1_MSTR;
break;
default:
debug("%s: Invalid i2s master selection\n", __func__);
return -1;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif |= WM8994_AIF1_LRCLK_INV;
case SND_SOC_DAIFMT_DSP_A:
aif |= 0x18;
break;
case SND_SOC_DAIFMT_I2S:
aif |= 0x10;
break;
case SND_SOC_DAIFMT_RIGHT_J:
break;
case SND_SOC_DAIFMT_LEFT_J:
aif |= 0x8;
break;
default:
debug("%s: Invalid i2s format selection\n", __func__);
return -1;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
/* frame inversion not valid for DSP modes */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_NF:
aif |= WM8994_AIF1_BCLK_INV;
break;
default:
debug("%s: Invalid i2s frame inverse selection\n",
__func__);
return -1;
}
break;
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_LEFT_J:
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
aif |= WM8994_AIF1_BCLK_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
aif |= WM8994_AIF1_LRCLK_INV;
break;
default:
debug("%s: Invalid i2s clock polarity selection\n",
__func__);
return -1;
}
break;
default:
debug("%s: Invalid i2s format selection\n", __func__);
return -1;
}
error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV |
WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif);
error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms);
error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK,
WM8994_AIF1CLK_ENA);
if (error < 0) {
debug("%s: codec register access error\n", __func__);
return -1;
}
return 0;
+}
+/*
- Sets hw params FOR WM8994
- @param sampling_rate Sampling rate
- @param bits_per_sample Bits per sample
- @param Channels Channels in the given audio input
should document every parameter
- @return -1 for error and 0 Success.
- */
+static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
unsigned int sampling_rate, unsigned int bits_per_sample,
unsigned int channels)
+{
int aif1_reg;
int aif2_reg;
int bclk_reg;
int bclk = 0;
int rate_reg;
int aif1 = 0;
int aif2 = 0;
int rate_val = 0;
int id = aif_id - 1;
int i, cur_val, best_val, bclk_rate, best;
unsigned short reg_data;
int ret = 0;
switch (aif_id) {
case 1:
aif1_reg = WM8994_AIF1_CONTROL_1;
aif2_reg = WM8994_AIF1_CONTROL_2;
bclk_reg = WM8994_AIF1_BCLK;
rate_reg = WM8994_AIF1_RATE;
break;
case 2:
aif1_reg = WM8994_AIF2_CONTROL_1;
aif2_reg = WM8994_AIF2_CONTROL_2;
bclk_reg = WM8994_AIF2_BCLK;
rate_reg = WM8994_AIF2_RATE;
break;
default:
return -1;
}
bclk_rate = sampling_rate * 32;
switch (bits_per_sample) {
case 16:
bclk_rate *= 16;
break;
case 20:
bclk_rate *= 20;
aif1 |= 0x20;
break;
case 24:
bclk_rate *= 24;
aif1 |= 0x40;
break;
case 32:
bclk_rate *= 32;
aif1 |= 0x60;
break;
default:
return -1;
}
/* Try to find an appropriate sample rate; look for an exact match. */
for (i = 0; i < ARRAY_SIZE(src_rate); i++)
if (src_rate[i] == sampling_rate)
break;
if (i == ARRAY_SIZE(src_rate)) {
debug("%s: Could not get the best matching samplingrate\n",
__func__);
return -1;
}
rate_val |= i << WM8994_AIF1_SR_SHIFT;
/* AIFCLK/fs ratio; look for a close match in either direction */
best = 0;
best_val = abs((fs_ratios[0] * sampling_rate)
- wm8994->aifclk[id]);
for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
cur_val = abs((fs_ratios[i] * sampling_rate)
- wm8994->aifclk[id]);
if (cur_val >= best_val)
continue;
best = i;
best_val = cur_val;
}
rate_val |= best;
/*
* We may not get quite the right frequency if using
* approximate clocks so look for the closest match that is
* higher than the target (we need to ensure that there enough
* BCLKs to clock out the samples).
*/
best = 0;
for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
if (cur_val < 0) /* BCLK table is sorted */
break;
best = i;
}
if (i == ARRAY_SIZE(bclk_divs)) {
debug("%s: Could not get the best matching bclk division\n",
__func__);
return -1;
}
bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
if (wm8994_i2c_read(aif1_reg, ®_data) != 0)
return -1;
debug() here
if ((channels == 1) && ((reg_data & 0x18) == 0x18))
aif2 |= WM8994_AIF1_MONO;
if (wm8994->aifclk[id] == 0)
return -1;
debug() here
ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1);
ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2);
ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK |
WM8994_AIF1CLK_RATE_MASK, rate_val);
debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
if (ret < 0) {
debug("%s: codec register access error\n", __func__);
return -1;
}
return 0;
+}
+/*
- Configures Audio interface Clock
- @param wm8994 wm8994 information pointer
- @param aif Audio Interface ID
- @return -1 for error and 0 Success.
- */
+static int configure_aif_clock(struct wm8994_priv *wm8994, int aif) +{
int rate;
int reg1 = 0;
int offset;
int ret;
if (aif)
offset = 4;
else
offset = 0;
comment? What does offset mean?
switch (wm8994->sysclk[aif]) {
case WM8994_SYSCLK_MCLK1:
reg1 |= SEL_MCLK1;
rate = wm8994->mclk[0];
break;
case WM8994_SYSCLK_MCLK2:
reg1 |= SEL_MCLK2;
rate = wm8994->mclk[1];
break;
case WM8994_SYSCLK_FLL1:
reg1 |= SEL_FLL1;
rate = wm8994->fll[0].out;
break;
case WM8994_SYSCLK_FLL2:
reg1 |= SEL_FLL2;
rate = wm8994->fll[1].out;
break;
default:
debug("%s: Invalid input clock selection [%d]\n",
__func__, wm8994->sysclk[aif]);
return -1;
}
/* if input clock frequenct is more than 135Mhz then divide */
if (rate >= WM8994_MAX_INPUT_CLK_FREQ) {
rate /= 2;
reg1 |= WM8994_AIF1CLK_DIV;
}
wm8994->aifclk[aif] = 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,
WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
if (ret < 0) {
debug("%s: codec register access error\n", __func__);
return -1;
}
return 0;
+}
+/*
- Configures Audio interface for the given frequency
- @param wm8994 wm8994 information
- @param aif_id Audio Interface
- @param clk_id Input Clock ID
- @param freq Sampling frequency in Hz
- @return -1 for error and 0 success.
- */
+static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
int clk_id, unsigned int freq)
+{
int i;
int ret = 0;
wm8994->sysclk[aif_id - 1] = clk_id;
switch (clk_id) {
case WM8994_SYSCLK_MCLK1:
wm8994->mclk[0] = freq;
if (aif_id == 2) {
ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 ,
WM8994_AIF2DAC_DIV_MASK , 0);
}
break;
case WM8994_SYSCLK_MCLK2:
/* TODO: Set GPIO AF */
wm8994->mclk[1] = freq;
break;
case WM8994_SYSCLK_FLL1:
case WM8994_SYSCLK_FLL2:
break;
case WM8994_SYSCLK_OPCLK:
/* Special case - a division (times 10) is given and
/* * Special case ...
* no effect on main clocking.
*/
if (freq) {
for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
if (opclk_divs[i] == freq)
break;
if (i == ARRAY_SIZE(opclk_divs))
return -1;
debug()
ret = wm8994_update_bits(WM8994_CLOCKING_2,
WM8994_OPCLK_DIV_MASK, i);
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
} else {
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
WM8994_OPCLK_ENA, 0);
}
default:
debug("%s Invalid input clock selection [%d]\n",
__func__, clk_id);
return -1;
}
ret |= configure_aif_clock(wm8994, aif_id - 1);
if (ret < 0) {
debug("%s: codec register access error\n", __func__);
return -1;
}
return 0;
+}
+/*
- Initializes Volume for AIF2 to HP path
- @returns -1 for error and 0 Success.
- */
+static int wm8994_init_volume_aif2_dac1(void) +{
int ret;
/* Unmute AIF2DAC */
ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1,
WM8994_AIF2DAC_MUTE_MASK, 0);
ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME,
WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
WM8994_AIF2DAC_VU | 0xff);
ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME,
WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
WM8994_AIF2DAC_VU | 0xff);
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) +{
const char *devname;
unsigned short reg_data;
int ret;
wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */
ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, ®_data);
if (ret < 0) {
debug("Failed to read ID register\n");
goto err;
}
if (reg_data == WM8994_ID) {
devname = "WM8994";
debug("Device registered as type %d\n", wm8994->type);
wm8994->type = WM8994;
} else {
debug("Device is not a WM8994, ID is %x\n", ret);
ret = -1;
goto err;
}
ret = wm8994_i2c_read(WM8994_CHIP_REVISION, ®_data);
if (ret < 0) {
debug("Failed to read revision register: %d\n", ret);
goto err;
}
wm8994->revision = reg_data;
debug("%s revision %c\n", devname, 'A' + wm8994->revision);
/* VMID Selection */
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
/* Charge Pump Enable */
ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
WM8994_CP_ENA);
/* Head Phone Power Enable */
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
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);
/* Head Phone Initialisation */
ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK,
WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY);
ret |= wm8994_update_bits(WM8994_DC_SERVO_1,
WM8994_DCS_ENA_CHAN_0_MASK |
WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 |
WM8994_DCS_ENA_CHAN_1);
ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
WM8994_HPOUT1L_DLY_MASK |
WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
WM8994_HPOUT1R_OUTP_MASK |
WM8994_HPOUT1L_RMV_SHORT_MASK |
WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY |
WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP |
WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT |
WM8994_HPOUT1R_RMV_SHORT);
/* MIXER Config DAC1 to HP */
ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1,
WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L);
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 (ret < 0)
goto err;
debug("%s: Codec chip init ok\n", __func__);
return 0;
+err:
debug("%s: Codec chip init error\n", __func__);
return -1;
+}
+/*wm8994 Device Initialisation */ +int wm8994_init(struct sound_codec_info *pcodec_info,
enum en_audio_interface aif_id,
int sampling_rate, int mclk_freq,
int bits_per_sample, unsigned int channels)
+{
int ret = 0;
/* shift the device address by 1 for 7 bit addressing */
g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
Would be better if the address was a 7-bit address?
wm8994_i2c_init(pcodec_info->i2c_bus);
if (pcodec_info->codec_type == CODEC_WM_8994)
g_wm8994_info.type = WM8994;
else {
debug("%s: Codec id [%d] not defined\n", __func__,
pcodec_info->codec_type);
return -1;
}
ret = wm8994_device_init(&g_wm8994_info);
if (ret < 0) {
debug("%s: wm8994 codec chip init failed\n", __func__);
return ret;
}
ret = wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1,
mclk_freq);
if (ret < 0) {
debug("%s: wm8994 codec set sys clock failed\n", __func__);
return ret;
}
ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate,
bits_per_sample, channels);
if (ret == 0) {
ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS);
}
return ret;
+} diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h new file mode 100644 index 0000000..3c12cbb --- /dev/null +++ b/drivers/sound/wm8994.h @@ -0,0 +1,87 @@ +/*
- Copyright (C) 2012 Samsung Electronics
- R. Chadrasekar rcsekar@samsung.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#ifndef __WM8994_H__ +#define __WM8994_H__
+/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ +#define WM8994_SYSCLK_MCLK1 1 +#define WM8994_SYSCLK_MCLK2 2 +#define WM8994_SYSCLK_FLL1 3 +#define WM8994_SYSCLK_FLL2 4
+/* Avilable audi interface ports in wm8994 codec */ +enum en_audio_interface {
WM8994_AIF1 = 1,
WM8994_AIF2,
WM8994_AIF3
+};
+/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ +#define WM8994_SYSCLK_OPCLK 5
+#define WM8994_FLL1 1 +#define WM8994_FLL2 2
+#define WM8994_FLL_SRC_MCLK1 1 +#define WM8994_FLL_SRC_MCLK2 2 +#define WM8994_FLL_SRC_LRCLK 3 +#define WM8994_FLL_SRC_BCLK 4
+/* maximum available digital interfac in the dac to configure */ +#define WM8994_MAX_AIF 2
+#define WM8994_MAX_INPUT_CLK_FREQ 13500000 +#define WM8994_ID 0x8994
+enum wm8994_vmid_mode {
WM8994_VMID_NORMAL,
WM8994_VMID_FORCE,
+};
+/* wm 8994 family devices */ +enum wm8994_type {
WM8994 = 0,
WM8958 = 1,
WM1811 = 2,
+};
+/*
- intialise wm8994 sound codec device for the given configuration
- @param pcodec_info pointer value of the sound codec info structure
parsed from device tree
- @param aif_id enum value of codec interface port in which
soc i2s is connected
- @param sampling_rate Sampling rate
- @param mclk_freq MCLK Frequency
- @param bits_per_sample bits per Sample
- @param channels Number of channnels
Really there should be some information about suitable values here. The comments are almost just repeating the variable names. What are valid values for 'channels'. For mclk_freq, what should this be set to?
- @returns -1 for error and 0 Success.
- */
+int wm8994_init(struct sound_codec_info *pcodec_info,
enum en_audio_interface aif_id,
int sampling_rate, int mclk_freq,
int bits_per_sample, unsigned int channels);
+#endif /*__WM8994_H__ */ diff --git a/drivers/sound/wm8994_registers.h b/drivers/sound/wm8994_registers.h new file mode 100644 index 0000000..dacf6b6 --- /dev/null +++ b/drivers/sound/wm8994_registers.h @@ -0,0 +1,299 @@ +/*
- (C) Copyright 2012 Samsung Electronics
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
- */
+#ifndef __MFD_WM8994_REGISTERS_H__ +#define __MFD_WM8994_REGISTERS_H__
Should remove MFD_ I think
+/*
- Register values.
- */
+#define WM8994_SOFTWARE_RESET 0x00 +#define WM8994_POWER_MANAGEMENT_1 0x01 +#define WM8994_POWER_MANAGEMENT_2 0x02 +#define WM8994_POWER_MANAGEMENT_5 0x05 +#define WM8994_LEFT_OUTPUT_VOLUME 0x1C +#define WM8994_RIGHT_OUTPUT_VOLUME 0x1D +#define WM8994_OUTPUT_MIXER_1 0x2D +#define WM8994_OUTPUT_MIXER_2 0x2E +#define WM8994_CHARGE_PUMP_1 0x4C +#define WM8994_DC_SERVO_1 0x54 +#define WM8994_ANALOGUE_HP_1 0x60 +#define WM8994_CHIP_REVISION 0x100 +#define WM8994_AIF1_CLOCKING_1 0x200 +#define WM8994_AIF1_CLOCKING_2 0x201 +#define WM8994_AIF2_CLOCKING_1 0x204 +#define WM8994_CLOCKING_1 0x208 +#define WM8994_CLOCKING_2 0x209 +#define WM8994_AIF1_RATE 0x210 +#define WM8994_AIF2_RATE 0x211 +#define WM8994_RATE_STATUS 0x212 +#define WM8994_AIF1_CONTROL_1 0x300 +#define WM8994_AIF1_CONTROL_2 0x301 +#define WM8994_AIF1_MASTER_SLAVE 0x302 +#define WM8994_AIF1_BCLK 0x303 +#define WM8994_AIF2_CONTROL_1 0x310 +#define WM8994_AIF2_CONTROL_2 0x311 +#define WM8994_AIF2_MASTER_SLAVE 0x312 +#define WM8994_AIF2_BCLK 0x313 +#define WM8994_AIF2_DAC_LEFT_VOLUME 0x502 +#define WM8994_AIF2_DAC_RIGHT_VOLUME 0x503 +#define WM8994_AIF2_DAC_FILTERS_1 0x520 +#define WM8994_DAC1_LEFT_MIXER_ROUTING 0x601 +#define WM8994_DAC1_RIGHT_MIXER_ROUTING 0x602 +#define WM8994_DAC1_LEFT_VOLUME 0x610 +#define WM8994_DAC1_RIGHT_VOLUME 0x611 +#define WM8994_GPIO_3 0x702 +#define WM8994_GPIO_4 0x703 +#define WM8994_GPIO_5 0x704
+/*
- Field Definitions.
- */
+/*
- R0 (0x00) - Software Reset
- */
+/* SW_RESET */ +#define WM8994_SW_RESET 1 +/*
- R1 (0x01) - Power Management (1)
- */
+/* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA 0x0200 +/* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA_MASK 0x0200 +/* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA 0x0100 +/* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA_MASK 0x0100 +/* VMID_SEL - [2:1] */ +#define WM8994_VMID_SEL_MASK 0x0006 +/* BIAS_ENA */ +#define WM8994_BIAS_ENA 0x0001 +/* BIAS_ENA */ +#define WM8994_BIAS_ENA_MASK 0x0001
+/*
- R2 (0x02) - Power Management (2)
- */
+/* OPCLK_ENA */ +#define WM8994_OPCLK_ENA 0x0800
+/*
- R5 (0x05) - Power Management (5)
- */
+/* AIF2DACL_ENA */ +#define WM8994_AIF2DACL_ENA 0x2000 +#define WM8994_AIF2DACL_ENA_MASK 0x2000 +/* AIF2DACR_ENA */ +#define WM8994_AIF2DACR_ENA 0x1000 +#define WM8994_AIF2DACR_ENA_MASK 0x1000 +/* DAC1L_ENA */ +#define WM8994_DAC1L_ENA 0x0002 +#define WM8994_DAC1L_ENA_MASK 0x0002 +/* DAC1R_ENA */ +#define WM8994_DAC1R_ENA 0x0001 +#define WM8994_DAC1R_ENA_MASK 0x0001
+/*
- R45 (0x2D) - Output Mixer (1)
- */
+/* DAC1L_TO_HPOUT1L */ +#define WM8994_DAC1L_TO_HPOUT1L 0x0100 +#define WM8994_DAC1L_TO_HPOUT1L_MASK 0x0100
+/*
- R46 (0x2E) - Output Mixer (2)
- */
+/* DAC1R_TO_HPOUT1R */ +#define WM8994_DAC1R_TO_HPOUT1R 0x0100 +#define WM8994_DAC1R_TO_HPOUT1R_MASK 0x0100
+/*
- R76 (0x4C) - Charge Pump (1)
- */
+/* CP_ENA */ +#define WM8994_CP_ENA 0x8000 +#define WM8994_CP_ENA_MASK 0x8000 +/*
- R84 (0x54) - DC Servo (1)
- */
+/* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_1 0x0002 +#define WM8994_DCS_ENA_CHAN_1_MASK 0x0002 +/* DCS_ENA_CHAN_0 */ +#define WM8994_DCS_ENA_CHAN_0 0x0001 +#define WM8994_DCS_ENA_CHAN_0_MASK 0x0001
+/*
- R96 (0x60) - Analogue HP (1)
- */
+/* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_RMV_SHORT 0x0080 +#define WM8994_HPOUT1L_RMV_SHORT_MASK 0x0080 +/* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_OUTP 0x0040 +#define WM8994_HPOUT1L_OUTP_MASK 0x0040 +/* HPOUT1L_DLY */ +#define WM8994_HPOUT1L_DLY 0x0020 +#define WM8994_HPOUT1L_DLY_MASK 0x0020 +/* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_RMV_SHORT 0x0008 +#define WM8994_HPOUT1R_RMV_SHORT_MASK 0x0008 +/* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_OUTP 0x0004 +#define WM8994_HPOUT1R_OUTP_MASK 0x0004 +/* HPOUT1R_DLY */ +#define WM8994_HPOUT1R_DLY 0x0002 +#define WM8994_HPOUT1R_DLY_MASK 0x0002
+/*
- R512 (0x200) - AIF1 Clocking (1)
- */
+/* AIF1CLK_SRC - [4:3] */ +#define WM8994_AIF1CLK_SRC_MASK 0x0018 +/* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_DIV 0x0002 +/* AIF1CLK_ENA */ +#define WM8994_AIF1CLK_ENA 0x0001 +#define WM8994_AIF1CLK_ENA_MASK 0x0001
+/*
- R517 (0x205) - AIF2 Clocking (2)
- */
+/* AIF2DAC_DIV - [5:3] */ +#define WM8994_AIF2DAC_DIV_MASK 0x0038
+/*
- R520 (0x208) - Clocking (1)
- */
+/* AIF2DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA 0x0004 +#define WM8994_AIF2DSPCLK_ENA_MASK 0x0004 +/* SYSDSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA 0x0002 +#define WM8994_SYSDSPCLK_ENA_MASK 0x0002 +/* SYSCLK_SRC */ +#define WM8994_SYSCLK_SRC 0x0001
+/*
- R521 (0x209) - Clocking (2)
- */
+/* OPCLK_DIV - [2:0] */ +#define WM8994_OPCLK_DIV_MASK 0x0007
+/*
- R528 (0x210) - AIF1 Rate
- */
+/* AIF1_SR - [7:4] */ +#define WM8994_AIF1_SR_MASK 0x00F0 +#define WM8994_AIF1_SR_SHIFT 4 +/* AIF1CLK_RATE - [3:0] */ +#define WM8994_AIF1CLK_RATE_MASK 0x000F
+/*
- R768 (0x300) - AIF1 Control (1)
- */
+/* AIF1_BCLK_INV */ +#define WM8994_AIF1_BCLK_INV 0x0100 +/* AIF1_LRCLK_INV */ +#define WM8994_AIF1_LRCLK_INV 0x0080 +#define WM8994_AIF1_LRCLK_INV_MASK 0x0080 +/* AIF1_WL - [6:5] */ +#define WM8994_AIF1_WL_MASK 0x0060 +/* AIF1_FMT - [4:3] */ +#define WM8994_AIF1_FMT_MASK 0x0018
+/*
- R769 (0x301) - AIF1 Control (2)
- */
+/* AIF1_MONO */ +#define WM8994_AIF1_MONO 0x0100
+/*
- R770 (0x302) - AIF1 Master/Slave
- */
+/* AIF1_MSTR */ +#define WM8994_AIF1_MSTR 0x4000 +#define WM8994_AIF1_MSTR_MASK 0x4000
+/*
- R771 (0x303) - AIF1 BCLK
- */
+/* AIF1_BCLK_DIV - [8:4] */ +#define WM8994_AIF1_BCLK_DIV_MASK 0x01F0 +#define WM8994_AIF1_BCLK_DIV_SHIFT 4
+/*
- R1282 (0x502) - AIF2 DAC Left Volume
- */
+/* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU 0x0100 +#define WM8994_AIF2DAC_VU_MASK 0x0100 +/* AIF2DACL_VOL - [7:0] */ +#define WM8994_AIF2DACL_VOL_MASK 0x00FF
+/*
- R1283 (0x503) - AIF2 DAC Right Volume
- */
+/* AIF2DACR_VOL - [7:0] */ +#define WM8994_AIF2DACR_VOL_MASK 0x00FF
+/*
- R1312 (0x520) - AIF2 DAC Filters (1)
- */
+/* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MUTE_MASK 0x0200
+/*
- R1537 (0x601) - DAC1 Left Mixer Routing
- */
+/* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L 0x0004 +#define WM8994_AIF2DACL_TO_DAC1L_MASK 0x0004
+/*
- R1538 (0x602) - DAC1 Right Mixer Routing
- */
+/* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R 0x0004 +#define WM8994_AIF2DACR_TO_DAC1R_MASK 0x0004
+/*
- R1552 (0x610) - DAC1 Left Volume
- */
+/* DAC1L_MUTE */ +#define WM8994_DAC1L_MUTE_MASK 0x0200 +/* DAC1_VU */ +#define WM8994_DAC1_VU 0x0100 +#define WM8994_DAC1_VU_MASK 0x0100 +/* DAC1L_VOL - [7:0] */ +#define WM8994_DAC1L_VOL_MASK 0x00FF
+/*
- R1553 (0x611) - DAC1 Right Volume
- */
+/* DAC1R_MUTE */ +#define WM8994_DAC1R_MUTE_MASK 0x0200 +/* DAC1R_VOL - [7:0] */ +#define WM8994_DAC1R_VOL_MASK 0x00FF
+/*
- GPIO
- */
+/* OUTPUT PIN */ +#define WM8994_GPIO_DIR_OUTPUT 0x8000 +/* GPIO PIN MASK */ +#define WM8994_GPIO_DIR_MASK 0xFFE0 +/* I2S CLK */ +#define WM8994_GPIO_FUNCTION_I2S_CLK 0x0000 +/* GPn FN */ +#define WM8994_GPIO_FUNCTION_MASK 0x001F
+#endif
1.7.4.4
Regards, Simon

This patch adds command to test audio playback. sound init - Initialises the audio subsystem (i2s and wm8994 codec) sound play - Plays predefined the audio data.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - None common/Makefile | 1 + common/cmd_sound.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 0 deletions(-) create mode 100644 common/cmd_sound.c
diff --git a/common/Makefile b/common/Makefile index 483eb4d..a21cac9 100644 --- a/common/Makefile +++ b/common/Makefile @@ -73,6 +73,7 @@ COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o COBJS-$(CONFIG_CMD_DATE) += cmd_date.o +COBJS-$(CONFIG_CMD_SOUND) += cmd_sound.o ifdef CONFIG_4xx COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o endif diff --git a/common/cmd_sound.c b/common/cmd_sound.c new file mode 100644 index 0000000..9684435 --- /dev/null +++ b/common/cmd_sound.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Rajeshwari Shinde rajeshwari.s@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <fdtdec.h> +#include <sound.h> + +/* globaldata */ +DECLARE_GLOBAL_DATA_PTR; + +/* Initilaise sound subsystem */ +static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int ret; + + ret = sound_init(); + if (ret) { + printf("Initialise Audio driver failed\n"); + return CMD_RET_FAILURE; + } + + return 0; +} + +/* play sound from buffer */ +static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int ret = 0; + + ret = sound_play(); + if (ret) { + printf("play failed"); + return CMD_RET_FAILURE; + } + + return 0; +} + +static cmd_tbl_t cmd_sound_sub[] = { + U_BOOT_CMD_MKENT(init, 0, 1, do_init, "", ""), + U_BOOT_CMD_MKENT(play, 2, 1, do_play, "", ""), +}; + +/* process sound command */ +static int do_sound(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + cmd_tbl_t *c; + + if (argc < 1) + return CMD_RET_USAGE; + + /* Strip off leading 'sound' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], &cmd_sound_sub[0], ARRAY_SIZE(cmd_sound_sub)); + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +U_BOOT_CMD( + sound, 3, 1, do_sound, + "sound sub-system", + "init - initialise the sound driver\n" + "sound play - play predefind sound\n" +);

Hi Rajeshwari,
On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds command to test audio playback. sound init - Initialises the audio subsystem (i2s and wm8994 codec) sound play - Plays predefined the audio data.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Changes in V2:
- None
common/Makefile | 1 + common/cmd_sound.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 0 deletions(-) create mode 100644 common/cmd_sound.c
diff --git a/common/Makefile b/common/Makefile index 483eb4d..a21cac9 100644 --- a/common/Makefile +++ b/common/Makefile @@ -73,6 +73,7 @@ COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o COBJS-$(CONFIG_CMD_DATE) += cmd_date.o +COBJS-$(CONFIG_CMD_SOUND) += cmd_sound.o ifdef CONFIG_4xx COBJS-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o endif diff --git a/common/cmd_sound.c b/common/cmd_sound.c new file mode 100644 index 0000000..9684435 --- /dev/null +++ b/common/cmd_sound.c @@ -0,0 +1,90 @@ +/*
- Copyright (C) 2012 Samsung Electronics
- Rajeshwari Shinde rajeshwari.s@samsung.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#include <common.h> +#include <command.h> +#include <fdtdec.h> +#include <sound.h>
+/* globaldata */
Maybe remove this comment?
+DECLARE_GLOBAL_DATA_PTR;
+/* Initilaise sound subsystem */ +static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{
int ret;
ret = sound_init();
if (ret) {
printf("Initialise Audio driver failed\n");
return CMD_RET_FAILURE;
}
return 0;
+}
+/* play sound from buffer */ +static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{
int ret = 0;
ret = sound_play();
if (ret) {
printf("play failed");
return CMD_RET_FAILURE;
}
return 0;
+}
+static cmd_tbl_t cmd_sound_sub[] = {
U_BOOT_CMD_MKENT(init, 0, 1, do_init, "", ""),
U_BOOT_CMD_MKENT(play, 2, 1, do_play, "", ""),
+};
+/* process sound command */ +static int do_sound(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{
cmd_tbl_t *c;
if (argc < 1)
return CMD_RET_USAGE;
/* Strip off leading 'sound' command argument */
argc--;
argv++;
c = find_cmd_tbl(argv[0], &cmd_sound_sub[0], ARRAY_SIZE(cmd_sound_sub));
if (c)
return c->cmd(cmdtp, flag, argc, argv);
else
return CMD_RET_USAGE;
+}
+U_BOOT_CMD(
sound, 3, 1, do_sound,
"sound sub-system",
"init - initialise the sound driver\n"
"sound play - play predefind sound\n"
pre-defined
+);
1.7.4.4
Regards, Simon

This patch add I2S registers
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - None arch/arm/include/asm/arch-exynos/i2s-regs.h | 66 +++++++++++++++++++++++++++ 1 files changed, 66 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/i2s-regs.h
diff --git a/arch/arm/include/asm/arch-exynos/i2s-regs.h b/arch/arm/include/asm/arch-exynos/i2s-regs.h new file mode 100644 index 0000000..2326ca0 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/i2s-regs.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar rcsekar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __I2S_REGS_H__ +#define __I2S_REGS_H__ + +#define CON_TXFIFO_FULL (1 << 8) +#define CON_TXCH_PAUSE (1 << 4) +#define CON_ACTIVE (1 << 0) + +#define MOD_BLCP_SHIFT 24 +#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT) +#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT) +#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT) +#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT) + +#define MOD_BLC_16BIT (0 << 13) +#define MOD_BLC_8BIT (1 << 13) +#define MOD_BLC_24BIT (2 << 13) +#define MOD_BLC_MASK (3 << 13) + +#define MOD_SLAVE (1 << 11) +#define MOD_MASK (3 << 8) +#define MOD_LR_LLOW (0 << 7) +#define MOD_LR_RLOW (1 << 7) +#define MOD_SDF_IIS (0 << 5) +#define MOD_SDF_MSB (1 << 5) +#define MOD_SDF_LSB (2 << 5) +#define MOD_SDF_MASK (3 << 5) +#define MOD_RCLK_256FS (0 << 3) +#define MOD_RCLK_512FS (1 << 3) +#define MOD_RCLK_384FS (2 << 3) +#define MOD_RCLK_768FS (3 << 3) +#define MOD_RCLK_MASK (3 << 3) +#define MOD_BCLK_32FS (0 << 1) +#define MOD_BCLK_48FS (1 << 1) +#define MOD_BCLK_16FS (2 << 1) +#define MOD_BCLK_24FS (3 << 1) +#define MOD_BCLK_MASK (3 << 1) + +#define MOD_CDCLKCON (1 << 12) + +#define FIC_TXFLUSH (1 << 15) +#define FIC_RXFLUSH (1 << 7) + +#endif /* __I2S_REGS_H__ */

On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch add I2S registers
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
Changes in V2:
- None
arch/arm/include/asm/arch-exynos/i2s-regs.h | 66 +++++++++++++++++++++++++++ 1 files changed, 66 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/i2s-regs.h
diff --git a/arch/arm/include/asm/arch-exynos/i2s-regs.h b/arch/arm/include/asm/arch-exynos/i2s-regs.h new file mode 100644 index 0000000..2326ca0 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/i2s-regs.h @@ -0,0 +1,66 @@ +/*
- Copyright (C) 2012 Samsung Electronics
- R. Chandrasekar rcsekar@samsung.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#ifndef __I2S_REGS_H__ +#define __I2S_REGS_H__
+#define CON_TXFIFO_FULL (1 << 8) +#define CON_TXCH_PAUSE (1 << 4) +#define CON_ACTIVE (1 << 0)
+#define MOD_BLCP_SHIFT 24 +#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT) +#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT) +#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT) +#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT)
+#define MOD_BLC_16BIT (0 << 13) +#define MOD_BLC_8BIT (1 << 13) +#define MOD_BLC_24BIT (2 << 13) +#define MOD_BLC_MASK (3 << 13)
+#define MOD_SLAVE (1 << 11) +#define MOD_MASK (3 << 8) +#define MOD_LR_LLOW (0 << 7) +#define MOD_LR_RLOW (1 << 7) +#define MOD_SDF_IIS (0 << 5) +#define MOD_SDF_MSB (1 << 5) +#define MOD_SDF_LSB (2 << 5) +#define MOD_SDF_MASK (3 << 5) +#define MOD_RCLK_256FS (0 << 3) +#define MOD_RCLK_512FS (1 << 3) +#define MOD_RCLK_384FS (2 << 3) +#define MOD_RCLK_768FS (3 << 3) +#define MOD_RCLK_MASK (3 << 3) +#define MOD_BCLK_32FS (0 << 1) +#define MOD_BCLK_48FS (1 << 1) +#define MOD_BCLK_16FS (2 << 1) +#define MOD_BCLK_24FS (3 << 1) +#define MOD_BCLK_MASK (3 << 1)
+#define MOD_CDCLKCON (1 << 12)
+#define FIC_TXFLUSH (1 << 15) +#define FIC_RXFLUSH (1 << 7)
+#endif /* __I2S_REGS_H__ */
1.7.4.4

This patch adds the audio parameters required by the I2S to play the predefined audio data.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - None arch/arm/include/asm/arch-exynos/sound.h | 44 ++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/sound.h
diff --git a/arch/arm/include/asm/arch-exynos/sound.h b/arch/arm/include/asm/arch-exynos/sound.h new file mode 100644 index 0000000..d25d4f2 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/sound.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Rajeshwari Shinde rajeshwari.s@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __SOUND_ARCH_H__ +#define __SOUND_ARCH_H__ + +/* I2S values */ +#define I2S_PLL_CLK 192000000 +#define I2S_SAMPLING_RATE 48000 +#define I2S_BITS_PER_SAMPLE 16 +#define I2S_CHANNELS 2 +#define I2S_RFS 256 +#define I2S_BFS 32 + +/* I2C values */ +#define AUDIO_I2C_BUS 1 +#define AUDIO_I2C_REG 0x34 + +/* Audio Codec */ +#define AUDIO_CODEC "wm8994" + +#define AUDIO_COMPAT 1 +#endif

Hi,
On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds the audio parameters required by the I2S to play the predefined audio data.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
Really these should come from the device tree. In the absence of that they should be board CONFIG options. But since the device tree config is coming very soon, I think this is ok for now.
Changes in V2:
- None
arch/arm/include/asm/arch-exynos/sound.h | 44 ++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/sound.h
diff --git a/arch/arm/include/asm/arch-exynos/sound.h b/arch/arm/include/asm/arch-exynos/sound.h new file mode 100644 index 0000000..d25d4f2 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/sound.h @@ -0,0 +1,44 @@ +/*
- Copyright (C) 2012 Samsung Electronics
- Rajeshwari Shinde rajeshwari.s@samsung.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#ifndef __SOUND_ARCH_H__ +#define __SOUND_ARCH_H__
+/* I2S values */ +#define I2S_PLL_CLK 192000000 +#define I2S_SAMPLING_RATE 48000 +#define I2S_BITS_PER_SAMPLE 16 +#define I2S_CHANNELS 2 +#define I2S_RFS 256 +#define I2S_BFS 32
+/* I2C values */ +#define AUDIO_I2C_BUS 1 +#define AUDIO_I2C_REG 0x34
+/* Audio Codec */ +#define AUDIO_CODEC "wm8994"
+#define AUDIO_COMPAT 1
+#endif
1.7.4.4

This patch adds pinmux support for I2S1
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - made exynos_i2s_config pinmux function static. arch/arm/cpu/armv7/exynos/pinmux.c | 12 ++++++++++++ arch/arm/include/asm/arch-exynos/periph.h | 1 + 2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 13f75e0..ed82bc3 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -273,6 +273,15 @@ void exynos5_spi_config(int peripheral) } }
+static void exynos5_i2s_config(int peripheral) +{ + int i; + struct exynos5_gpio_part1 *gpio1 = + (struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); + for (i = 0; i < 5; i++) + s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02)); +} + static int exynos5_pinmux_config(int peripheral, int flags) { switch (peripheral) { @@ -307,6 +316,9 @@ static int exynos5_pinmux_config(int peripheral, int flags) case PERIPH_ID_SPI4: exynos5_spi_config(peripheral); break; + case PERIPH_ID_I2S1: + exynos5_i2s_config(peripheral); + break; default: debug("%s: invalid peripheral %d", __func__, peripheral); return -1; diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index dafc3f3..404e5db 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -38,6 +38,7 @@ enum periph_id { PERIPH_ID_I2C5, PERIPH_ID_I2C6, PERIPH_ID_I2C7, + PERIPH_ID_I2S1, PERIPH_ID_SDMMC0, PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2,

Hi Rajeshwari,
On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds pinmux support for I2S1
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
Changes in V2:
- made exynos_i2s_config pinmux function static.
arch/arm/cpu/armv7/exynos/pinmux.c | 12 ++++++++++++ arch/arm/include/asm/arch-exynos/periph.h | 1 + 2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 13f75e0..ed82bc3 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -273,6 +273,15 @@ void exynos5_spi_config(int peripheral) } }
+static void exynos5_i2s_config(int peripheral) +{
int i;
struct exynos5_gpio_part1 *gpio1 =
(struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1();
blank line after
for (i = 0; i < 5; i++)
s5p_gpio_cfg_pin(&gpio1->b0, i, GPIO_FUNC(0x02));
+}
static int exynos5_pinmux_config(int peripheral, int flags) { switch (peripheral) { @@ -307,6 +316,9 @@ static int exynos5_pinmux_config(int peripheral, int flags) case PERIPH_ID_SPI4: exynos5_spi_config(peripheral); break;
case PERIPH_ID_I2S1:
exynos5_i2s_config(peripheral);
break; default: debug("%s: invalid peripheral %d", __func__, peripheral); return -1;
diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index dafc3f3..404e5db 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -38,6 +38,7 @@ enum periph_id { PERIPH_ID_I2C5, PERIPH_ID_I2C6, PERIPH_ID_I2C7,
PERIPH_ID_I2S1, PERIPH_ID_SDMMC0, PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2,
-- 1.7.4.4
Regards, Simon

This patch adds base address for I2S
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - None arch/arm/include/asm/arch-exynos/cpu.h | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 252a5b3..f32e778 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -55,6 +55,7 @@ #define EXYNOS4_PWMTIMER_BASE 0x139D0000 #define EXYNOS4_MODEM_BASE 0x13A00000 #define EXYNOS4_USBPHY_CONTROL 0x10020704 +#define EXYNOS4_I2S_BASE 0xE2100000
#define EXYNOS4_GPIO_PART4_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_DP_BASE DEVICE_NOT_AVAILABLE @@ -84,6 +85,7 @@ #define EXYNOS5_UART_BASE 0x12C00000 #define EXYNOS5_I2C_BASE 0x12C60000 #define EXYNOS5_SPI_BASE 0x12D20000 +#define EXYNOS5_I2S_BASE 0x12D60000 #define EXYNOS5_PWMTIMER_BASE 0x12DD0000 #define EXYNOS5_SPI_ISP_BASE 0x131A0000 #define EXYNOS5_GPIO_PART2_BASE 0x13400000 @@ -160,6 +162,7 @@ SAMSUNG_BASE(dp, DP_BASE) SAMSUNG_BASE(sysreg, SYSREG_BASE) SAMSUNG_BASE(fimd, FIMD_BASE) SAMSUNG_BASE(i2c, I2C_BASE) +SAMSUNG_BASE(i2s, I2S_BASE) SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE) SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE) SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE)

Hi,
On 22 August 2012 12:14, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds base address for I2S
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Chander Kashyap chander.kashyap@gmail.com

On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds base address for I2S
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
Changes in V2:
- None
arch/arm/include/asm/arch-exynos/cpu.h | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 252a5b3..f32e778 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -55,6 +55,7 @@ #define EXYNOS4_PWMTIMER_BASE 0x139D0000 #define EXYNOS4_MODEM_BASE 0x13A00000 #define EXYNOS4_USBPHY_CONTROL 0x10020704 +#define EXYNOS4_I2S_BASE 0xE2100000
#define EXYNOS4_GPIO_PART4_BASE DEVICE_NOT_AVAILABLE #define EXYNOS4_DP_BASE DEVICE_NOT_AVAILABLE @@ -84,6 +85,7 @@ #define EXYNOS5_UART_BASE 0x12C00000 #define EXYNOS5_I2C_BASE 0x12C60000 #define EXYNOS5_SPI_BASE 0x12D20000 +#define EXYNOS5_I2S_BASE 0x12D60000 #define EXYNOS5_PWMTIMER_BASE 0x12DD0000 #define EXYNOS5_SPI_ISP_BASE 0x131A0000 #define EXYNOS5_GPIO_PART2_BASE 0x13400000 @@ -160,6 +162,7 @@ SAMSUNG_BASE(dp, DP_BASE) SAMSUNG_BASE(sysreg, SYSREG_BASE) SAMSUNG_BASE(fimd, FIMD_BASE) SAMSUNG_BASE(i2c, I2C_BASE) +SAMSUNG_BASE(i2s, I2S_BASE) SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE) SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE) SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE) -- 1.7.4.4

This patch adds clock support for I2S
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - None arch/arm/cpu/armv7/exynos/clock.c | 119 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 +++++++ 3 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 44dff2b..691f6d4 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -26,6 +26,16 @@ #include <asm/arch/clock.h> #include <asm/arch/clk.h>
+/* Epll Clock division values to achive different frequency output */ +static struct st_epll_con_val epll_div[] = { + { 192000000, 0, 48, 3, 1, 0 }, + { 180000000, 0, 45, 3, 1, 0 }, + { 73728000, 1, 73, 3, 3, 47710 }, + { 67737600, 1, 90, 4, 3, 20762 }, + { 49152000, 0, 49, 3, 3, 9961 }, + { 45158400, 0, 45, 3, 3, 10381 }, + { 180633600, 0, 45, 3, 1, 10381 } +}; /* exynos4: return pll clock frequency */ static unsigned long exynos4_get_pll_clk(int pllreg) { @@ -848,6 +858,92 @@ static int exynos5_spi_set_clock_rate(enum periph_id periph_id, return 0; }
+int exynos5_clock_epll_set_rate(unsigned long rate) +{ + unsigned int epll_con, epll_con_k; + unsigned int i; + unsigned int lockcnt; + unsigned int start; + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + epll_con = readl(&clk->epll_con0); + epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << + EPLL_CON0_LOCK_DET_EN_SHIFT) | + EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT | + EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT | + EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT); + + for (i = 0; i < ARRAY_SIZE(epll_div); i++) { + if (epll_div[i].freq_out == rate) + break; + } + + if (i == ARRAY_SIZE(epll_div)) + return -1; + + epll_con_k = epll_div[i].k_dsm << 0; + epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT; + epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT; + epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT; + epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT; + + /* + * Required period ( in cycles) to genarate a stable clock output. + * The maximum clock time can be up to 3000 * PDIV cycles of PLLs + * frequency input (as per spec) + */ + lockcnt = 3000 * epll_div[i].p_div; + + writel(lockcnt, &clk->epll_lock); + writel(epll_con, &clk->epll_con0); + writel(epll_con_k, &clk->epll_con1); + + start = get_timer(0); + + while (!(readl(&clk->epll_con0) & + (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { + if (get_timer(start) > TIMEOUT_EPLL_LOCK) { + debug("%s: Timeout waiting for EPLL lock\n", __func__); + return -1; + } + } + return 0; +} + +void exynos5_clock_select_i2s_clk_source(void) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, + (CLK_SRC_SCLK_EPLL)); +} + +int exynos5_clock_set_i2s_clk_prescaler(unsigned int src_frq, + unsigned int dst_frq) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned int div; + + if ((dst_frq == 0) || (src_frq == 0)) { + debug("%s: Invalid requency input for prescaler\n", __func__); + debug("src frq = %d des frq = %d ", src_frq, dst_frq); + return -1; + } + + 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; + } + clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, + (div & AUDIO_1_RATIO_MASK)); + return 0; +} + unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -927,3 +1023,26 @@ int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate) else return 0; } + +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +{ + + if (cpu_is_exynos5()) + return exynos5_clock_set_i2s_clk_prescaler(src_frq, dst_frq); + else + return 0; +} + +void clock_select_i2s_clk_source(void) +{ + if (cpu_is_exynos5()) + exynos5_clock_select_i2s_clk_source(); +} + +int clock_epll_set_rate(unsigned long rate) +{ + if (cpu_is_exynos5()) + return exynos5_clock_epll_set_rate(rate); + else + return 0; +} diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 4e51402..f32c634 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -41,4 +41,7 @@ unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate); +void clock_select_i2s_clk_source(void); +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +int clock_epll_set_rate(unsigned long rate); #endif diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index fce38ef..1df49a9 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -595,9 +595,38 @@ struct exynos5_clock { unsigned int pll_div2_sel; unsigned char res123[0xf5d8]; }; + +/* structure for epll configuration used in audio clock configuration */ +struct st_epll_con_val { + unsigned int freq_out; /* frequency out */ + unsigned int en_lock_det; /* enable lock detect */ + unsigned int m_div; /* m divider value */ + unsigned int p_div; /* p divider value */ + unsigned int s_div; /* s divider value */ + unsigned int k_dsm; /* k value of delta signal modulator */ +}; #endif
#define MPLL_FOUT_SEL_SHIFT 4 +#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/ +#define TIMEOUT_EPLL_LOCK 1000 + +#define AUDIO_0_RATIO_MASK 0x0f +#define AUDIO_1_RATIO_MASK 0x0f + +#define AUDIO1_SEL_MASK 0xf +#define CLK_SRC_SCLK_EPLL 0x7 + +/* CON0 bit-fields */ +#define EPLL_CON0_MDIV_MASK 0x1ff +#define EPLL_CON0_PDIV_MASK 0x3f +#define EPLL_CON0_SDIV_MASK 0x7 +#define EPLL_CON0_MDIV_SHIFT 16 +#define EPLL_CON0_PDIV_SHIFT 8 +#define EPLL_CON0_SDIV_SHIFT 0 +#define EPLL_CON0_LOCK_DET_EN_SHIFT 28 +#define EPLL_CON0_LOCK_DET_EN_MASK 1 + #define MPLL_FOUT_SEL_MASK 0x1 #define BPLL_FOUT_SEL_SHIFT 0 #define BPLL_FOUT_SEL_MASK 0x1

On 22 August 2012 12:14, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds clock support for I2S
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Changes in V2:
- None
arch/arm/cpu/armv7/exynos/clock.c | 119 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 +++++++ 3 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 44dff2b..691f6d4 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -26,6 +26,16 @@ #include <asm/arch/clock.h> #include <asm/arch/clk.h>
+/* Epll Clock division values to achive different frequency output */ +static struct st_epll_con_val epll_div[] = {
{ 192000000, 0, 48, 3, 1, 0 },
{ 180000000, 0, 45, 3, 1, 0 },
{ 73728000, 1, 73, 3, 3, 47710 },
{ 67737600, 1, 90, 4, 3, 20762 },
{ 49152000, 0, 49, 3, 3, 9961 },
{ 45158400, 0, 45, 3, 3, 10381 },
{ 180633600, 0, 45, 3, 1, 10381 }
+};
Are these division values common to Exynos or only for exynos-5.
/* exynos4: return pll clock frequency */ static unsigned long exynos4_get_pll_clk(int pllreg) { @@ -848,6 +858,92 @@ static int exynos5_spi_set_clock_rate(enum periph_id periph_id, return 0; }
+int exynos5_clock_epll_set_rate(unsigned long rate) +{
unsigned int epll_con, epll_con_k;
unsigned int i;
unsigned int lockcnt;
unsigned int start;
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
epll_con = readl(&clk->epll_con0);
epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
EPLL_CON0_LOCK_DET_EN_SHIFT) |
EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
if (epll_div[i].freq_out == rate)
break;
}
if (i == ARRAY_SIZE(epll_div))
return -1;
epll_con_k = epll_div[i].k_dsm << 0;
epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT;
epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
/*
* Required period ( in cycles) to genarate a stable clock output.
* The maximum clock time can be up to 3000 * PDIV cycles of PLLs
* frequency input (as per spec)
*/
lockcnt = 3000 * epll_div[i].p_div;
writel(lockcnt, &clk->epll_lock);
writel(epll_con, &clk->epll_con0);
writel(epll_con_k, &clk->epll_con1);
start = get_timer(0);
while (!(readl(&clk->epll_con0) &
(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
debug("%s: Timeout waiting for EPLL lock\n", __func__);
return -1;
}
}
return 0;
+}
+void exynos5_clock_select_i2s_clk_source(void) +{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
(CLK_SRC_SCLK_EPLL));
+}
+int exynos5_clock_set_i2s_clk_prescaler(unsigned int src_frq,
unsigned int dst_frq)
+{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
unsigned int div;
if ((dst_frq == 0) || (src_frq == 0)) {
debug("%s: Invalid requency input for prescaler\n", __func__);
debug("src frq = %d des frq = %d ", src_frq, dst_frq);
return -1;
}
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;
}
clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
(div & AUDIO_1_RATIO_MASK));
return 0;
+}
unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -927,3 +1023,26 @@ int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate) else return 0; }
+int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +{
if (cpu_is_exynos5())
return exynos5_clock_set_i2s_clk_prescaler(src_frq, dst_frq);
else
return 0;
+}
+void clock_select_i2s_clk_source(void) +{
if (cpu_is_exynos5())
exynos5_clock_select_i2s_clk_source();
+}
+int clock_epll_set_rate(unsigned long rate) +{
if (cpu_is_exynos5())
return exynos5_clock_epll_set_rate(rate);
else
return 0;
+} diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 4e51402..f32c634 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -41,4 +41,7 @@ unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate); +void clock_select_i2s_clk_source(void); +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +int clock_epll_set_rate(unsigned long rate); #endif diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index fce38ef..1df49a9 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -595,9 +595,38 @@ struct exynos5_clock { unsigned int pll_div2_sel; unsigned char res123[0xf5d8]; };
+/* structure for epll configuration used in audio clock configuration */ +struct st_epll_con_val {
unsigned int freq_out; /* frequency out */
unsigned int en_lock_det; /* enable lock detect */
unsigned int m_div; /* m divider value */
unsigned int p_div; /* p divider value */
unsigned int s_div; /* s divider value */
unsigned int k_dsm; /* k value of delta signal modulator */
+}; #endif
#define MPLL_FOUT_SEL_SHIFT 4 +#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/ +#define TIMEOUT_EPLL_LOCK 1000
+#define AUDIO_0_RATIO_MASK 0x0f +#define AUDIO_1_RATIO_MASK 0x0f
+#define AUDIO1_SEL_MASK 0xf +#define CLK_SRC_SCLK_EPLL 0x7
+/* CON0 bit-fields */ +#define EPLL_CON0_MDIV_MASK 0x1ff +#define EPLL_CON0_PDIV_MASK 0x3f +#define EPLL_CON0_SDIV_MASK 0x7 +#define EPLL_CON0_MDIV_SHIFT 16 +#define EPLL_CON0_PDIV_SHIFT 8 +#define EPLL_CON0_SDIV_SHIFT 0 +#define EPLL_CON0_LOCK_DET_EN_SHIFT 28 +#define EPLL_CON0_LOCK_DET_EN_MASK 1
#define MPLL_FOUT_SEL_MASK 0x1 #define BPLL_FOUT_SEL_SHIFT 0
#define BPLL_FOUT_SEL_MASK 0x1
1.7.4.4

On 22 August 2012 15:44, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds clock support for I2S
Signed-off-by: R. Chandrasekar rcsekar@samsung.com Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Changes in V2:
- None
arch/arm/cpu/armv7/exynos/clock.c | 119 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 +++++++ 3 files changed, 151 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 44dff2b..691f6d4 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -26,6 +26,16 @@ #include <asm/arch/clock.h> #include <asm/arch/clk.h>
+/* Epll Clock division values to achive different frequency output */ +static struct st_epll_con_val epll_div[] = {
{ 192000000, 0, 48, 3, 1, 0 },
{ 180000000, 0, 45, 3, 1, 0 },
{ 73728000, 1, 73, 3, 3, 47710 },
{ 67737600, 1, 90, 4, 3, 20762 },
{ 49152000, 0, 49, 3, 3, 9961 },
{ 45158400, 0, 45, 3, 3, 10381 },
{ 180633600, 0, 45, 3, 1, 10381 }
+}; /* exynos4: return pll clock frequency */ static unsigned long exynos4_get_pll_clk(int pllreg) { @@ -848,6 +858,92 @@ static int exynos5_spi_set_clock_rate(enum periph_id periph_id, return 0; }
+int exynos5_clock_epll_set_rate(unsigned long rate)
exynos5_set_epll_clk
+{
unsigned int epll_con, epll_con_k;
unsigned int i;
unsigned int lockcnt;
unsigned int start;
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
epll_con = readl(&clk->epll_con0);
epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
EPLL_CON0_LOCK_DET_EN_SHIFT) |
EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
if (epll_div[i].freq_out == rate)
break;
}
if (i == ARRAY_SIZE(epll_div))
return -1;
epll_con_k = epll_div[i].k_dsm << 0;
epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT;
epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
/*
* Required period ( in cycles) to genarate a stable clock output.
* The maximum clock time can be up to 3000 * PDIV cycles of PLLs
* frequency input (as per spec)
*/
lockcnt = 3000 * epll_div[i].p_div;
writel(lockcnt, &clk->epll_lock);
writel(epll_con, &clk->epll_con0);
writel(epll_con_k, &clk->epll_con1);
start = get_timer(0);
while (!(readl(&clk->epll_con0) &
(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
debug("%s: Timeout waiting for EPLL lock\n", __func__);
return -1;
}
}
return 0;
+}
+void exynos5_clock_select_i2s_clk_source(void)
exynos5_set_i2s_clk_source
+{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
(CLK_SRC_SCLK_EPLL));
+}
+int exynos5_clock_set_i2s_clk_prescaler(unsigned int src_frq,
exynos5_set_i2s_clk_prescaler
unsigned int dst_frq)
+{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
unsigned int div;
if ((dst_frq == 0) || (src_frq == 0)) {
debug("%s: Invalid requency input for prescaler\n", __func__);
debug("src frq = %d des frq = %d ", src_frq, dst_frq);
return -1;
}
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;
}
clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
(div & AUDIO_1_RATIO_MASK));
return 0;
+}
unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -927,3 +1023,26 @@ int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate) else return 0; }
+int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
set_i2s_clk_prescaler
+{
if (cpu_is_exynos5())
return exynos5_clock_set_i2s_clk_prescaler(src_frq, dst_frq);
else
return 0;
+}
+void clock_select_i2s_clk_source(void)
set_i2s_clk_source
+{
if (cpu_is_exynos5())
exynos5_clock_select_i2s_clk_source();
+}
+int clock_epll_set_rate(unsigned long rate)
set_epll_clk
+{
if (cpu_is_exynos5())
return exynos5_clock_epll_set_rate(rate);
else
return 0;
+} diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 4e51402..f32c634 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -41,4 +41,7 @@ unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void); int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate); +void clock_select_i2s_clk_source(void); +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); +int clock_epll_set_rate(unsigned long rate); #endif diff --git a/arch/arm/include/asm/arch-exynos/clock.h b/arch/arm/include/asm/arch-exynos/clock.h index fce38ef..1df49a9 100644 --- a/arch/arm/include/asm/arch-exynos/clock.h +++ b/arch/arm/include/asm/arch-exynos/clock.h @@ -595,9 +595,38 @@ struct exynos5_clock { unsigned int pll_div2_sel; unsigned char res123[0xf5d8]; };
+/* structure for epll configuration used in audio clock configuration */ +struct st_epll_con_val {
unsigned int freq_out; /* frequency out */
unsigned int en_lock_det; /* enable lock detect */
unsigned int m_div; /* m divider value */
unsigned int p_div; /* p divider value */
unsigned int s_div; /* s divider value */
unsigned int k_dsm; /* k value of delta signal modulator */
+}; #endif
#define MPLL_FOUT_SEL_SHIFT 4 +#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/ +#define TIMEOUT_EPLL_LOCK 1000
+#define AUDIO_0_RATIO_MASK 0x0f +#define AUDIO_1_RATIO_MASK 0x0f
+#define AUDIO1_SEL_MASK 0xf +#define CLK_SRC_SCLK_EPLL 0x7
+/* CON0 bit-fields */ +#define EPLL_CON0_MDIV_MASK 0x1ff +#define EPLL_CON0_PDIV_MASK 0x3f +#define EPLL_CON0_SDIV_MASK 0x7 +#define EPLL_CON0_MDIV_SHIFT 16 +#define EPLL_CON0_PDIV_SHIFT 8 +#define EPLL_CON0_SDIV_SHIFT 0 +#define EPLL_CON0_LOCK_DET_EN_SHIFT 28 +#define EPLL_CON0_LOCK_DET_EN_MASK 1
#define MPLL_FOUT_SEL_MASK 0x1 #define BPLL_FOUT_SEL_SHIFT 0
#define BPLL_FOUT_SEL_MASK 0x1
1.7.4.4
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Thanks. Minkyu Kang.

This patch enables sound support for EXYNOS5
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- Changes in V2: - corrected the commit message. include/configs/smdk5250.h | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index 29b7ac6..1463137 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -237,6 +237,14 @@ #define CONFIG_ENV_SPI_MAX_HZ 50000000 #endif
+/* Sound */ +#define CONFIG_CMD_SOUND +#ifdef CONFIG_CMD_SOUND +#define CONFIG_SOUND +#define CONFIG_I2S +#define CONFIG_SOUND_WM8994 +#endif + /* Enable devicetree support */ #define CONFIG_OF_LIBFDT

On 22 August 2012 12:14, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch enables sound support for EXYNOS5
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Chander Kashyap chander.kashyap@linaro.org

On Tue, Aug 21, 2012 at 11:44 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch enables sound support for EXYNOS5
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
Changes in V2:
- corrected the commit message.
include/configs/smdk5250.h | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index 29b7ac6..1463137 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -237,6 +237,14 @@ #define CONFIG_ENV_SPI_MAX_HZ 50000000 #endif
+/* Sound */ +#define CONFIG_CMD_SOUND +#ifdef CONFIG_CMD_SOUND +#define CONFIG_SOUND +#define CONFIG_I2S +#define CONFIG_SOUND_WM8994 +#endif
/* Enable devicetree support */ #define CONFIG_OF_LIBFDT
-- 1.7.4.4

Hi All,
Do let me know if any more comments on this patchset.
Regards, Rajeshwari Shinde.
On Wed, Aug 22, 2012 at 12:14 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patchset adds the audio support for EXYNOS5. This patchset plays a predefined beep sound.
This patchset is based on the following patches: "[U-Boot] [PATCH 1/7 V4] EXYNOS5: Add pinmux support for SPI" "[U-Boot] [PATCH 4/7 V3] EXYNOS5: Add base address for SPI" "[U-Boot] [PATCH 3/7 V3] EXYNOS: Add clock for SPI"
Changes in V2:
- renamed i2s.c to samsung-i2s.c.
- made exynos_i2s_config pinmux function static.
- corrected the commit message for "Enable sound" patch.
Rajeshwari Shinde (9): SOUND: Add I2S driver SOUND: Add WM8994 codec Sound: Add command for audio playback EXYNOS: Add I2S registers EXYNOS: Add parameters required by I2S EXYNOS: Add pinmux for I2S EXYNOS: Add I2S base address EXYNOS: Add clock for I2S SMDK5250: Enable Sound
Makefile | 1 + arch/arm/cpu/armv7/exynos/clock.c | 119 ++++ arch/arm/cpu/armv7/exynos/pinmux.c | 12 + arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 + arch/arm/include/asm/arch-exynos/cpu.h | 3 + arch/arm/include/asm/arch-exynos/i2s-regs.h | 66 +++ arch/arm/include/asm/arch-exynos/periph.h | 1 + arch/arm/include/asm/arch-exynos/sound.h | 44 ++ common/Makefile | 1 + common/cmd_sound.c | 90 +++ drivers/sound/Makefile | 48 ++ drivers/sound/samsung-i2s.c | 358 ++++++++++++ drivers/sound/sound.c | 220 ++++++++ drivers/sound/wm8994.c | 781 +++++++++++++++++++++++++++ drivers/sound/wm8994.h | 87 +++ drivers/sound/wm8994_registers.h | 299 ++++++++++ include/configs/smdk5250.h | 8 + include/i2s.h | 127 +++++ include/sound.h | 62 +++ 20 files changed, 2359 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/i2s-regs.h create mode 100644 arch/arm/include/asm/arch-exynos/sound.h create mode 100644 common/cmd_sound.c create mode 100644 drivers/sound/Makefile create mode 100644 drivers/sound/samsung-i2s.c create mode 100644 drivers/sound/sound.c create mode 100644 drivers/sound/wm8994.c create mode 100644 drivers/sound/wm8994.h create mode 100644 drivers/sound/wm8994_registers.h create mode 100644 include/i2s.h create mode 100644 include/sound.h
-- 1.7.4.4
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi All,
Please do let me know if any comments on these patch set.
Regards, Rajeshwari Shinde.
On Thu, Sep 13, 2012 at 11:07 AM, Rajeshwari Birje rajeshwari.birje@gmail.com wrote:
Hi All,
Do let me know if any more comments on this patchset.
Regards, Rajeshwari Shinde.
On Wed, Aug 22, 2012 at 12:14 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patchset adds the audio support for EXYNOS5. This patchset plays a predefined beep sound.
This patchset is based on the following patches: "[U-Boot] [PATCH 1/7 V4] EXYNOS5: Add pinmux support for SPI" "[U-Boot] [PATCH 4/7 V3] EXYNOS5: Add base address for SPI" "[U-Boot] [PATCH 3/7 V3] EXYNOS: Add clock for SPI"
Changes in V2:
- renamed i2s.c to samsung-i2s.c.
- made exynos_i2s_config pinmux function static.
- corrected the commit message for "Enable sound" patch.
Rajeshwari Shinde (9): SOUND: Add I2S driver SOUND: Add WM8994 codec Sound: Add command for audio playback EXYNOS: Add I2S registers EXYNOS: Add parameters required by I2S EXYNOS: Add pinmux for I2S EXYNOS: Add I2S base address EXYNOS: Add clock for I2S SMDK5250: Enable Sound
Makefile | 1 + arch/arm/cpu/armv7/exynos/clock.c | 119 ++++ arch/arm/cpu/armv7/exynos/pinmux.c | 12 + arch/arm/include/asm/arch-exynos/clk.h | 3 + arch/arm/include/asm/arch-exynos/clock.h | 29 + arch/arm/include/asm/arch-exynos/cpu.h | 3 + arch/arm/include/asm/arch-exynos/i2s-regs.h | 66 +++ arch/arm/include/asm/arch-exynos/periph.h | 1 + arch/arm/include/asm/arch-exynos/sound.h | 44 ++ common/Makefile | 1 + common/cmd_sound.c | 90 +++ drivers/sound/Makefile | 48 ++ drivers/sound/samsung-i2s.c | 358 ++++++++++++ drivers/sound/sound.c | 220 ++++++++ drivers/sound/wm8994.c | 781 +++++++++++++++++++++++++++ drivers/sound/wm8994.h | 87 +++ drivers/sound/wm8994_registers.h | 299 ++++++++++ include/configs/smdk5250.h | 8 + include/i2s.h | 127 +++++ include/sound.h | 62 +++ 20 files changed, 2359 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-exynos/i2s-regs.h create mode 100644 arch/arm/include/asm/arch-exynos/sound.h create mode 100644 common/cmd_sound.c create mode 100644 drivers/sound/Makefile create mode 100644 drivers/sound/samsung-i2s.c create mode 100644 drivers/sound/sound.c create mode 100644 drivers/sound/wm8994.c create mode 100644 drivers/sound/wm8994.h create mode 100644 drivers/sound/wm8994_registers.h create mode 100644 include/i2s.h create mode 100644 include/sound.h
-- 1.7.4.4
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
participants (5)
-
Chander Kashyap
-
Minkyu Kang
-
Rajeshwari Birje
-
Rajeshwari Shinde
-
Simon Glass