[alsa-devel] [PATCH 0/3] Add WM8580 PCM Machine driver for Samsung SoCs
Hi,
This patchset is for WM8580 pcm machine driver that supports PCM audio on SMDKC110, SMDKV210, SMDK6450, SMDK6440. and It is tested on SMDKC110, SMDKV210, SMDKV6450.
Based on these patches WM8580 pcm machine driver supports followings: o Playback supports 8kHz sampling rates. o Capture supports 8kHz sampling rates.
This patchset contains followings
o To Kukjin Kim and Ben Dooks, [PATCH 1/3] ARM: S5PV210: Add PCM audio support for WM8580 [PATCH 2/3] ARM: S5P64X0: Add PCM audio support for WM8580
o To Jassi Brar, Mark Brown and Liam Girdwood, [PATCH 3/3] ASoC: SAMSUNG: Add WM8580 PCM Machine driver
This patch-set is based on 2.6.39-rc1 and WM8580 machine driver is originated by Seungwhan Youn.
Best Regards, SB Kim (Sangbeom Kim)
This patch add pcm audio configuration for SMDKV210 and SMDKC110. Platform device and pcm clock initialization code is added.
Signed-off-by: Sangbeom Kim sbkim73@samsung.com --- arch/arm/mach-s5pv210/clock.c | 90 ++++++++++++++++++++++- arch/arm/mach-s5pv210/cpu.c | 7 ++- arch/arm/mach-s5pv210/include/mach/map.h | 2 + arch/arm/mach-s5pv210/include/mach/regs-audss.h | 45 +++++++++++ arch/arm/mach-s5pv210/mach-smdkc110.c | 1 + arch/arm/mach-s5pv210/mach-smdkv210.c | 1 + arch/arm/plat-s5p/include/plat/map-s5p.h | 1 + 7 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-s5pv210/include/mach/regs-audss.h
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index 2d59949..a964e1c 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c @@ -21,6 +21,7 @@ #include <linux/io.h>
#include <mach/map.h> +#include <mach/regs-audss.h>
#include <plat/cpu-freq.h> #include <mach/regs-clock.h> @@ -185,6 +186,11 @@ static int s5pv210_clk_mask1_ctrl(struct clk *clk, int enable) return s5p_gatectrl(S5P_CLK_SRC_MASK1, clk, enable); }
+static int s5pv210_clk_audss_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_AUDSS, clk, enable); +} + static struct clk clk_sclk_hdmi27m = { .name = "sclk_hdmi27m", .id = -1, @@ -208,17 +214,28 @@ static struct clk clk_sclk_usbphy1 = {
static struct clk clk_pcmcdclk0 = { .name = "pcmcdclk", - .id = -1, + .id = 0, + .rate = 2048000, };
static struct clk clk_pcmcdclk1 = { .name = "pcmcdclk", - .id = -1, + .id = 1, };
static struct clk clk_pcmcdclk2 = { .name = "pcmcdclk", - .id = -1, + .id = 2, +}; + +static struct clk clk_i2scdclk0 = { + .name = "i2scdclk", + .id = 0, +}; + +static struct clk clk_i2scdclk1 = { + .name = "i2scdclk", + .id = 1, };
static struct clk *clkset_vpllsrc_list[] = { @@ -490,6 +507,24 @@ static struct clk init_clocks_off[] = { .parent = &clk_p, .enable = s5pv210_clk_ip3_ctrl, .ctrlbit = (1 << 0), + }, { + .name = "pcm", + .id = 0, + .parent = &clk_pclk_psys.clk, + .enable = s5pv210_clk_ip3_ctrl, + .ctrlbit = (1 << 28), + }, { + .name = "pcm", + .id = 1, + .parent = &clk_pclk_psys.clk, + .enable = s5pv210_clk_ip3_ctrl, + .ctrlbit = (1 << 29), + }, { + .name = "pcm", + .id = 2, + .parent = &clk_pclk_psys.clk, + .enable = s5pv210_clk_ip3_ctrl, + .ctrlbit = (1 << 30), }, };
@@ -714,6 +749,48 @@ static struct clksrc_clk clk_sclk_audio2 = { .reg_div = { .reg = S5P_CLK_DIV6, .shift = 8, .size = 4 }, };
+static struct clk *clkset_mout_audss_list[] = { + NULL, + &clk_fout_epll, +}; + +static struct clksrc_sources clkset_mout_audss = { + .sources = clkset_mout_audss_list, + .nr_sources = ARRAY_SIZE(clkset_mout_audss_list), +}; + +static struct clksrc_clk clk_mout_audss = { + .clk = { + .name = "mout_audss", + .id = -1, + }, + .sources = &clkset_mout_audss, + .reg_src = { .reg = S5P_CLKSRC_AUDSS, .shift = 0, .size = 1 }, +}; + +static struct clk *clkset_sclk_audss_list[] = { + &clk_mout_audss.clk, + &clk_i2scdclk0, + &clk_sclk_audio0.clk, +}; + +static struct clksrc_sources clkset_sclk_audss = { + .sources = clkset_sclk_audss_list, + .nr_sources = ARRAY_SIZE(clkset_sclk_audss_list), +}; + +static struct clksrc_clk clk_sclk_audss = { + .clk = { + .name = "audio-bus", + .id = -1, + .enable = s5pv210_clk_audss_ctrl, + .ctrlbit = (1 << 6), + }, + .sources = &clkset_sclk_audss, + .reg_src = { .reg = S5P_CLKSRC_AUDSS, .shift = 2, .size = 2 }, + .reg_div = { .reg = S5P_CLKDIV_AUDSS, .shift = 4, .size = 4 }, +}; + static struct clk *clkset_sclk_spdif_list[] = { [0] = &clk_sclk_audio0.clk, [1] = &clk_sclk_audio1.clk, @@ -1058,6 +1135,8 @@ static struct clksrc_clk *sysclks[] = { &clk_sclk_hdmi, &clk_mout_dmc0, &clk_sclk_dmc0, + &clk_mout_audss, + &clk_sclk_audss, &clk_sclk_audio0, &clk_sclk_audio1, &clk_sclk_audio2, @@ -1212,6 +1291,9 @@ void __init_or_cpufreq s5pv210_setup_clocks(void)
for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) s3c_set_clksrc(&clksrcs[ptr], true); + + clk_set_parent(&clk_sclk_audio0.clk, &clk_pcmcdclk0); + clk_set_parent(&clk_sclk_audss.clk, &clk_sclk_audio0.clk); }
static struct clk *clks[] __initdata = { @@ -1219,6 +1301,8 @@ static struct clk *clks[] __initdata = { &clk_sclk_hdmiphy, &clk_sclk_usbphy0, &clk_sclk_usbphy1, + &clk_i2scdclk0, + &clk_i2scdclk1, &clk_pcmcdclk0, &clk_pcmcdclk1, &clk_pcmcdclk2, diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c index 61e6c24..4aa98ad 100644 --- a/arch/arm/mach-s5pv210/cpu.c +++ b/arch/arm/mach-s5pv210/cpu.c @@ -95,7 +95,12 @@ static struct map_desc s5pv210_iodesc[] __initdata = { .pfn =__phys_to_pfn(S5PV210_PA_HSPHY), .length = SZ_4K, .type = MT_DEVICE, - } + }, { + .virtual = (unsigned long)S5P_VA_AUDSS, + .pfn = __phys_to_pfn(S5PV210_PA_AUDSS), + .length = SZ_1K, + .type = MT_DEVICE, + }, };
static void s5pv210_idle(void) diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h index 1dd5883..195874e 100644 --- a/arch/arm/mach-s5pv210/include/mach/map.h +++ b/arch/arm/mach-s5pv210/include/mach/map.h @@ -64,6 +64,8 @@ #define S5PV210_PA_HSOTG 0xEC000000 #define S5PV210_PA_HSPHY 0xEC100000
+#define S5PV210_PA_AUDSS 0xEEE10000 + #define S5PV210_PA_IIS0 0xEEE30000 #define S5PV210_PA_IIS1 0xE2100000 #define S5PV210_PA_IIS2 0xE2A00000 diff --git a/arch/arm/mach-s5pv210/include/mach/regs-audss.h b/arch/arm/mach-s5pv210/include/mach/regs-audss.h new file mode 100644 index 0000000..2fa3c23 --- /dev/null +++ b/arch/arm/mach-s5pv210/include/mach/regs-audss.h @@ -0,0 +1,45 @@ +/* arch/arm/mach-s5pv210/include/mach/regs-clock.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5PV210 - Audio SubSystem clock register definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_AUDSS_H +#define __ASM_ARCH_REGS_AUDSS_H __FILE__ + +#define S5P_AUDSSREG(x) (S5P_VA_AUDSS + (x)) + +#define S5P_CLKSRC_AUDSS S5P_AUDSSREG(0x0) +#define S5P_CLKDIV_AUDSS S5P_AUDSSREG(0x4) +#define S5P_CLKGATE_AUDSS S5P_AUDSSREG(0x8) + +/* CLKSRC0 */ +#define S5P_AUDSS_CLKSRC_MAIN_MASK (0x1<<0) +#define S5P_AUDSS_CLKSRC_MAIN_SHIFT (0) +#define S5P_AUDSS_CLKSRC_BUSCLK_MASK (0x1<<1) +#define S5P_AUDSS_CLKSRC_BUSCLK_SHIFT (1) +#define S5P_AUDSS_CLKSRC_I2SCLK_MASK (0x3<<2) +#define S5P_AUDSS_CLKSRC_I2SCLK_SHIFT (2) + +/* CLKDIV0 */ +#define S5P_AUDSS_CLKDIV_BUSCLK_MASK (0xf<<0) +#define S5P_AUDSS_CLKDIV_BUSCLK_SHIFT (0) +#define S5P_AUDSS_CLKDIV_I2SCLK_MASK (0xf<<4) +#define S5P_AUDSS_CLKDIV_I2SCLK_SHIFT (4) + +/* IP Clock Gate 0 Registers */ +#define S5P_AUDSS_CLKGATE_HCLKRP (1<<0) +#define S5P_AUDSS_CLKGATE_HCLKBUF (1<<1) +#define S5P_AUDSS_CLKGATE_HCLKDMA (1<<2) +#define S5P_AUDSS_CLKGATE_HCLKHWA (1<<3) +#define S5P_AUDSS_CLKGATE_HCLKUART (1<<4) +#define S5P_AUDSS_CLKGATE_HCLKI2S (1<<5) +#define S5P_AUDSS_CLKGATE_CLKI2S (1<<6) + +#endif /* __ASM_ARCH_REGS_AUDSS_H */ diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c index 6c412c8..742a472 100644 --- a/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/arch/arm/mach-s5pv210/mach-smdkc110.c @@ -86,6 +86,7 @@ static struct platform_device *smdkc110_devices[] __initdata = { &s5pv210_device_iis0, &s5pv210_device_ac97, &s5pv210_device_spdif, + &s5pv210_device_pcm0, &s3c_device_cfcon, &s3c_device_i2c0, &s3c_device_i2c1, diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index c6a9e86..0346782 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -266,6 +266,7 @@ static struct platform_device *smdkv210_devices[] __initdata = { &s5pv210_device_ac97, &s5pv210_device_iis0, &s5pv210_device_spdif, + &s5pv210_device_pcm0, &samsung_asoc_dma, &samsung_device_keypad, &smdkv210_dm9000, diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h index d973d39..daa4a44 100644 --- a/arch/arm/plat-s5p/include/plat/map-s5p.h +++ b/arch/arm/plat-s5p/include/plat/map-s5p.h @@ -40,6 +40,7 @@ #define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000)
#define S3C_VA_USB_HSPHY S3C_ADDR(0x02900000) +#define S5P_VA_AUDSS S3C_ADDR(0x02A00000)
#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) #define VA_VIC0 VA_VIC(0)
This patch add pcm audio configuration for SMDK6450 and SMDK6440. Platform device and pcm clock initialization code is added.
Signed-off-by: Sangbeom Kim sbkim73@samsung.com --- arch/arm/mach-s5p64x0/clock-s5p6440.c | 63 +++++++++++--------- arch/arm/mach-s5p64x0/clock-s5p6450.c | 27 +++++++-- arch/arm/mach-s5p64x0/clock.c | 11 ++++ arch/arm/mach-s5p64x0/dev-audio.c | 56 ++++++++++++++++- arch/arm/mach-s5p64x0/include/mach/regs-clock.h | 3 + arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h | 4 + arch/arm/mach-s5p64x0/mach-smdk6440.c | 1 + arch/arm/mach-s5p64x0/mach-smdk6450.c | 1 + 8 files changed, 129 insertions(+), 37 deletions(-)
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c index 9f12c2e..3e03040 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6440.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c @@ -372,14 +372,12 @@ static struct clk init_clocks[] = { }, };
-static struct clk clk_iis_cd_v40 = { - .name = "iis_cdclk_v40", - .id = -1, -}; - -static struct clk clk_pcm_cd = { - .name = "pcm_cdclk", - .id = -1, +static struct clksrc_clk clk_dout_epll = { + .clk = { + .name = "dout_epll", + .id = -1, + .parent = &clk_mout_epll.clk, + }, };
static struct clk *clkset_group1_list[] = { @@ -403,17 +401,30 @@ static struct clksrc_sources clkset_uart = { .nr_sources = ARRAY_SIZE(clkset_uart_list), };
-static struct clk *clkset_audio_list[] = { - &clk_mout_epll.clk, - &clk_dout_mpll.clk, - &clk_fin_epll, - &clk_iis_cd_v40, - &clk_pcm_cd, +static struct clk *clkset_sclk_audio_list[] = { + [0] = &clk_dout_epll.clk, + [1] = &clk_dout_mpll.clk, + [2] = &clk_ext, + [3] = &clk_i2s_v40_cdclk, + [4] = &clk_pcmcdclk0, };
-static struct clksrc_sources clkset_audio = { - .sources = clkset_audio_list, - .nr_sources = ARRAY_SIZE(clkset_audio_list), +static struct clksrc_sources clkset_sclk_audio = { + .sources = clkset_sclk_audio_list, + .nr_sources = ARRAY_SIZE(clkset_sclk_audio_list), +}; + +struct clksrc_clk clk_sclk_audio = { + .clk = { + .name = "audio-bus", + .id = -1, + .enable = s5p64x0_sclk_ctrl, + .ctrlbit = (1 << 11), + .parent = &clk_ext_xtal_mux, + }, + .sources = &clkset_sclk_audio, + .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 }, + .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 }, };
static struct clksrc_clk clksrcs[] = { @@ -507,16 +518,6 @@ static struct clksrc_clk clksrcs[] = { .sources = &clkset_group1, .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 }, .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 }, - }, { - .clk = { - .name = "sclk_audio2", - .id = -1, - .ctrlbit = (1 << 11), - .enable = s5p64x0_sclk_ctrl, - }, - .sources = &clkset_audio, - .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 }, - .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 }, }, };
@@ -526,11 +527,13 @@ static struct clksrc_clk *sysclks[] = { &clk_mout_epll, &clk_mout_mpll, &clk_dout_mpll, + &clk_dout_epll, &clk_armclk, &clk_hclk, &clk_pclk, &clk_hclk_low, &clk_pclk_low, + &clk_sclk_audio, };
void __init_or_cpufreq s5p6440_setup_clocks(void) @@ -590,14 +593,16 @@ void __init_or_cpufreq s5p6440_setup_clocks(void) clk_h.rate = hclk; clk_p.rate = pclk;
+ clk_set_parent(&clk_sclk_audio.clk, &clk_pcmcdclk0); + for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) s3c_set_clksrc(&clksrcs[ptr], true); }
static struct clk *clks[] __initdata = { &clk_ext, - &clk_iis_cd_v40, - &clk_pcm_cd, + &clk_i2s_v40_cdclk, + &clk_pcmcdclk0, };
void __init s5p6440_register_clocks(void) diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c index 4eec457..27c7d4a 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6450.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c @@ -290,7 +290,14 @@ static struct clk init_clocks_off[] = { .parent = &clk_pclk.clk, .enable = s5p64x0_pclk_ctrl, .ctrlbit = (1 << 30), - } + }, { + .name = "pcm", + .id = 0, + .parent = &clk_pclk_low.clk, + .enable = s5p64x0_pclk_ctrl, + .ctrlbit = S5P_CLKCON_PCLK_PCM0, + }, + };
/* @@ -408,9 +415,9 @@ static struct clksrc_sources clkset_hsmmc44 = { static struct clk *clkset_sclk_audio0_list[] = { [0] = &clk_dout_epll.clk, [1] = &clk_dout_mpll.clk, - [2] = &clk_ext_xtal_mux, - [3] = NULL, - [4] = NULL, + [2] = &clk_ext, + [3] = &clk_i2s_v40_cdclk, + [4] = &clk_pcmcdclk0, };
static struct clksrc_sources clkset_sclk_audio0 = { @@ -418,7 +425,7 @@ static struct clksrc_sources clkset_sclk_audio0 = { .nr_sources = ARRAY_SIZE(clkset_sclk_audio0_list), };
-static struct clksrc_clk clk_sclk_audio0 = { +struct clksrc_clk clk_sclk_audio0 = { .clk = { .name = "audio-bus", .id = -1, @@ -647,12 +654,22 @@ void __init_or_cpufreq s5p6450_setup_clocks(void)
for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) s3c_set_clksrc(&clksrcs[ptr], true); + + clk_set_parent(&clk_sclk_audio0.clk, &clk_pcmcdclk0); }
+static struct clk *clks[] __initdata = { + &clk_ext, + &clk_i2s_v40_cdclk, + &clk_pcmcdclk0, +}; + void __init s5p6450_register_clocks(void) { int ptr;
+ s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); + for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) s3c_register_clksrc(sysclks[ptr], 1);
diff --git a/arch/arm/mach-s5p64x0/clock.c b/arch/arm/mach-s5p64x0/clock.c index b52c6e2..432bb06 100644 --- a/arch/arm/mach-s5p64x0/clock.c +++ b/arch/arm/mach-s5p64x0/clock.c @@ -233,3 +233,14 @@ int s5p64x0_clk48m_ctrl(struct clk *clk, int enable)
return 0; } + +struct clk clk_pcmcdclk0 = { + .name = "pcmcdclk", + .id = 0, + .rate = 4096000, +}; + +struct clk clk_i2s_v40_cdclk = { + .name = "i2s_v40_cdclk", + .id = 0, +}; diff --git a/arch/arm/mach-s5p64x0/dev-audio.c b/arch/arm/mach-s5p64x0/dev-audio.c index 35f1f22..a777363 100644 --- a/arch/arm/mach-s5p64x0/dev-audio.c +++ b/arch/arm/mach-s5p64x0/dev-audio.c @@ -207,7 +207,7 @@ static struct s3c_audio_pdata s5p6440_pcm_pdata = { .cfg_gpio = s5p6440_pcm_cfg_gpio, };
-static struct resource s5p6440_pcm0_resource[] = { +static struct resource s5p6440_pcm_resource[] = { [0] = { .start = S5P64X0_PA_PCM, .end = S5P64X0_PA_PCM + 0x100 - 1, @@ -228,9 +228,59 @@ static struct resource s5p6440_pcm0_resource[] = { struct platform_device s5p6440_device_pcm = { .name = "samsung-pcm", .id = 0, - .num_resources = ARRAY_SIZE(s5p6440_pcm0_resource), - .resource = s5p6440_pcm0_resource, + .num_resources = ARRAY_SIZE(s5p6440_pcm_resource), + .resource = s5p6440_pcm_resource, .dev = { .platform_data = &s5p6440_pcm_pdata, }, }; + +static int s5p6450_pcm_cfg_gpio(struct platform_device *pdev) +{ + switch (pdev->id) { + case 0: + s3c_gpio_cfgpin(S5P6450_GPR(4), S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin(S5P6450_GPR(7), S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin(S5P6450_GPR(8), S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin(S5P6450_GPR(13), S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin(S5P6450_GPR(14), S3C_GPIO_SFN(2)); + break; + default: + printk(KERN_DEBUG "Invalid PCM Controller number!"); + return -EINVAL; + } + + return 0; +} + +static struct s3c_audio_pdata s3c_pcm_pdata = { + .cfg_gpio = s5p6450_pcm_cfg_gpio, +}; + +static struct resource s5p6450_pcm0_resource[] = { + [0] = { + .start = S5P64X0_PA_PCM, + .end = S5P64X0_PA_PCM + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DMACH_PCM0_TX, + .end = DMACH_PCM0_TX, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = DMACH_PCM0_RX, + .end = DMACH_PCM0_RX, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device s5p6450_device_pcm0 = { + .name = "samsung-pcm", + .id = 0, + .num_resources = ARRAY_SIZE(s5p6450_pcm0_resource), + .resource = s5p6450_pcm0_resource, + .dev = { + .platform_data = &s3c_pcm_pdata, + }, +}; diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h index a133f22..9b72a1c 100644 --- a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h +++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h @@ -62,4 +62,7 @@
#define S5P_EPLL_CON S5P64X0_EPLL_CON
+#define S5P_CLKCON_SCLK0_AUDIO0 (1<<8) +#define S5P_CLKCON_PCLK_PCM0 (1<<8) + #endif /* __ASM_ARCH_REGS_CLOCK_H */ diff --git a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h index ff85b4b..88a8065 100644 --- a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h +++ b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h @@ -34,6 +34,10 @@ extern struct clksrc_clk clk_dout_mpll; extern struct clk *clkset_hclk_low_list[]; extern struct clksrc_sources clkset_hclk_low;
+extern struct clksrc_clk clk_sclk_audio0; +extern struct clk clk_pcmcdclk0; +extern struct clk clk_i2s_v40_cdclk; + extern int s5p64x0_pclk_ctrl(struct clk *clk, int enable); extern int s5p64x0_hclk0_ctrl(struct clk *clk, int enable); extern int s5p64x0_hclk1_ctrl(struct clk *clk, int enable); diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c index 2d559f1..2620cb4 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -139,6 +139,7 @@ static struct platform_device *smdk6440_devices[] __initdata = { &s3c_device_wdt, &samsung_asoc_dma, &s5p6440_device_iis, + &s5p6440_device_pcm, &s3c_device_timer[1], &smdk6440_backlight_device, }; diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c index d19c469..b573186 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -157,6 +157,7 @@ static struct platform_device *smdk6450_devices[] __initdata = { &s3c_device_wdt, &samsung_asoc_dma, &s5p6450_device_iis0, + &s5p6450_device_pcm0, &s3c_device_timer[1], &smdk6450_backlight_device, /* s5p6450_device_spi0 will be added */
This patch add WM8580 PCM machine driver to support PCM audio on SMDKC110, SMDKV210, SMDK6450, SMDK6440 boards. Playback and Capture supports 8kHz sampling rates. and It is tested on SMDKC110, SMDKV210, SMDK6450.
Signed-off-by: Sangbeom Kim sbkim73@samsung.com --- sound/soc/samsung/Kconfig | 12 +++ sound/soc/samsung/Makefile | 14 ++- sound/soc/samsung/pcm.c | 4 +- sound/soc/samsung/smdk_wm8580pcm.c | 190 ++++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 sound/soc/samsung/smdk_wm8580pcm.c
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index a3fdfb6..01f1560 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -23,6 +23,9 @@ config SND_S3C2412_SOC_I2S config SND_SAMSUNG_PCM tristate
+config SND_SOC_SAMSUNG_SMDK_WM8580_PCM + tristate + config SND_SAMSUNG_AC97 tristate select SND_SOC_AC97_BUS @@ -162,3 +165,12 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF select SND_SAMSUNG_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. + +config SND_SOC_SMDK_WM8580_PCM + tristate "SoC PCM Audio support for WM8580 on SMDK" + depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) + select SND_SOC_SAMSUNG_SMDK_WM8580_PCM if (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) + select SND_SOC_WM8580 + select SND_SAMSUNG_PCM + help + Say Y if you want to add support for SoC audio on the SMDK. diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 294dec0..fff9744 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -1,12 +1,12 @@ -# S3c24XX Platform Support +# SAMSUNG Platform Support snd-soc-s3c24xx-objs := dma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-ac97-objs := ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-samsung-spdif-objs := spdif.o -snd-soc-pcm-objs := pcm.o -snd-soc-i2s-objs := i2s.o +snd-soc-samsung-pcm-objs := pcm.o +snd-soc-samsung-i2s-objs := i2s.o
obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o @@ -14,10 +14,10 @@ obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o -obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o -obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o +obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-samsung-pcm.o +obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-samsung-i2s.o
-# S3C24XX Machine Support +# SAMSUNG Machine Support snd-soc-jive-wm8750-objs := jive_wm8750.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o @@ -34,6 +34,7 @@ snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-goni-wm8994-objs := goni_wm8994.o snd-soc-smdk-spdif-objs := smdk_spdif.o +snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -51,3 +52,4 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o +obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 38aac7d..9c7e8b4 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -350,8 +350,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, ctl = readl(regs + S3C_PCM_CTL);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - /* Nothing to do, NB_NF by default */ + case SND_SOC_DAIFMT_IB_NF: + /* Nothing to do, IB_NF by default */ break; default: dev_err(pcm->dev, "Unsupported clock inversion!\n"); diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c new file mode 100644 index 0000000..940eccc --- /dev/null +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -0,0 +1,190 @@ +/* + * sound/soc/samsung/smdk_wm8580pcm.c + * + * Copyright (c) 2011 Samsung Electronics Co. Ltd + * + * 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. + */ + +#include <sound/soc.h> +#include <sound/pcm_params.h> + +#include <asm/mach-types.h> + +#include "../codecs/wm8580.h" +#include "dma.h" +#include "pcm.h" + +/* + * Board Settings: + * o '1' means 'ON' + * o '0' means 'OFF' + * o 'X' means 'Don't care' + * + * SMDK6410, SMDK6440, SMDK6450 Base B/D: CFG1-0000, CFG2-1111 + * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000 + */ + +#define SMDK_WM8580_EXT_OSC 12000000 +#define SMDK_WM8580_EXT_MCLK 4096000 +#define SMDK_WM8580_EXT_VOICE 2048000 + +static unsigned long mclk_freq; +static unsigned long xtal_freq; + +/* + * If MCLK clock directly gets from XTAL, we don't have to use PLL + * to make MCLK, but if XTAL clock source connects with other codec + * pin (like XTI), we should have to set codec's PLL to make MCLK. + * Because Samsung SoC does not support pcmcdclk output like I2S. + */ + +static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int rfs, ret; + + switch (params_rate(params)) { + case 8000: + break; + default: + printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n", + __func__, __LINE__, params_rate(params)); + return -EINVAL; + } + + rfs = mclk_freq / params_rate(params) / 2; + + /* Set the codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B + | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* Set the cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B + | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + if (mclk_freq == xtal_freq) { + ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK, + mclk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, + WM8580_CLKSRC_MCLK); + if (ret < 0) + return ret; + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, + mclk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, + WM8580_CLKSRC_PLLA); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, + xtal_freq, mclk_freq); + if (ret < 0) + return ret; + } + + /* Set PCM source clock on CPU */ + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX, + mclk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* Set SCLK_DIV for making bclk */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops smdk_wm8580_pcm_ops = { + .hw_params = smdk_wm8580_pcm_hw_params, +}; + +static struct snd_soc_dai_link smdk_dai[] = { + { + .name = "WM8580 PAIF PCM RX", + .stream_name = "Playback", + .cpu_dai_name = "samsung-pcm.0", + .codec_dai_name = "wm8580-hifi-playback", + .platform_name = "samsung-audio", + .codec_name = "wm8580-codec.0-001b", + .ops = &smdk_wm8580_pcm_ops, + }, { + .name = "WM8580 PAIF PCM TX", + .stream_name = "Capture", + .cpu_dai_name = "samsung-pcm.0", + .codec_dai_name = "wm8580-hifi-capture", + .platform_name = "samsung-audio", + .codec_name = "wm8580-codec.0-001b", + .ops = &smdk_wm8580_pcm_ops, + }, +}; + +static struct snd_soc_card smdk = { + .name = "SMDK-PCM", + .dai_link = smdk_dai, + .num_links = 2, +}; + +static struct platform_device *smdk_snd_device; + +/* + * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1) + * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), + * 2.0484Mhz, directly with MCLK both Codec and SoC. + */ + +static int __init smdk_audio_init(void) +{ + int ret = 0; + + xtal_freq = SMDK_WM8580_EXT_OSC; + mclk_freq = SMDK_WM8580_EXT_MCLK; + + if (machine_is_smdkc110() || machine_is_smdkv210()) + xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE; + + smdk_snd_device = platform_device_alloc("soc-audio", -1); + if (!smdk_snd_device) + return -ENOMEM; + + platform_set_drvdata(smdk_snd_device, &smdk); + + ret = platform_device_add(smdk_snd_device); + if (ret) + platform_device_put(smdk_snd_device); + + return ret; +} + +module_init(smdk_audio_init); + +static void __exit smdk_audio_exit(void) +{ + platform_device_unregister(smdk_snd_device); +} +module_exit(smdk_audio_exit); + +MODULE_AUTHOR("Sangbeom Kim, sbkim73@samsung.com"); +MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM"); +MODULE_LICENSE("GPL");
On Thu, Apr 07, 2011 at 09:31:10AM +0900, Sangbeom Kim wrote:
+config SND_SOC_SAMSUNG_SMDK_WM8580_PCM
- tristate
What is the purpose of this variable? Just the config for the machine should be enough.
@@ -1,12 +1,12 @@ -# S3c24XX Platform Support +# SAMSUNG Platform Support snd-soc-s3c24xx-objs := dma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-ac97-objs := ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-samsung-spdif-objs := spdif.o -snd-soc-pcm-objs := pcm.o -snd-soc-i2s-objs := i2s.o +snd-soc-samsung-pcm-objs := pcm.o +snd-soc-samsung-i2s-objs := i2s.o
These changes all look reasonable but they're unrelated to adding the machine driver and should be split out.
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 38aac7d..9c7e8b4 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -350,8 +350,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, ctl = readl(regs + S3C_PCM_CTL);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
/* Nothing to do, NB_NF by default */
- case SND_SOC_DAIFMT_IB_NF:
break;/* Nothing to do, IB_NF by default */
Similarly here, this is a bug fix so should be merged for 2.6.39.
- smdk_snd_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_device)
return -ENOMEM;
Please use snd_soc_register_card() for new machines rather than the soc-audio device. Otherwise the actual driver itself looks good.
Hi Mark,
On Thu, Apr 07, 2011 at 10:17:10AM +0900, Mark Brown wrote:
+config SND_SOC_SAMSUNG_SMDK_WM8580_PCM
- tristate
What is the purpose of this variable? Just the config for the machine should be enough.
Ok, I will remove it and use machine config.
@@ -1,12 +1,12 @@ -# S3c24XX Platform Support +# SAMSUNG Platform Support snd-soc-s3c24xx-objs := dma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-ac97-objs := ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-samsung-spdif-objs := spdif.o -snd-soc-pcm-objs := pcm.o -snd-soc-i2s-objs := i2s.o +snd-soc-samsung-pcm-objs := pcm.o +snd-soc-samsung-i2s-objs := i2s.o
These changes all look reasonable but they're unrelated to adding the machine driver and should be split out.
Ok, I will split out.
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 38aac7d..9c7e8b4 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -350,8 +350,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai
*cpu_dai,
ctl = readl(regs + S3C_PCM_CTL);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
/* Nothing to do, NB_NF by default */
- case SND_SOC_DAIFMT_IB_NF:
break;/* Nothing to do, IB_NF by default */
Similarly here, this is a bug fix so should be merged for 2.6.39.
I will submit another bug fix patch for this.
- smdk_snd_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_device)
return -ENOMEM;
Please use snd_soc_register_card() for new machines rather than the soc-audio device. Otherwise the actual driver itself looks good.
Ok I will apply it.
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Thanks and Regards, SB Kim
+static struct snd_soc_dai_link smdk_dai[] = {
- {
- .name = "WM8580 PAIF PCM RX",
- .stream_name = "Playback",
- .cpu_dai_name = "samsung-pcm.0",
- .codec_dai_name = "wm8580-hifi-playback",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .ops = &smdk_wm8580_pcm_ops,
- }, {
- .name = "WM8580 PAIF PCM TX",
- .stream_name = "Capture",
- .cpu_dai_name = "samsung-pcm.0",
- .codec_dai_name = "wm8580-hifi-capture",
- .platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .ops = &smdk_wm8580_pcm_ops,
- },
+};
IIRC the PCM DAI is connected to Secondary i/f of WM8580 on some SMDKs. Isn't it smdk6410 ?
Hi! Jassi
On Thursday, April 07, 2011 12:43 PM, Jassi Brar wrote:
+static struct snd_soc_dai_link smdk_dai[] = {
{
.name = "WM8580 PAIF PCM RX",
.stream_name = "Playback",
.cpu_dai_name = "samsung-pcm.0",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
.ops = &smdk_wm8580_pcm_ops,
}, {
.name = "WM8580 PAIF PCM TX",
.stream_name = "Capture",
.cpu_dai_name = "samsung-pcm.0",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-audio",
.codec_name = "wm8580-codec.0-001b",
.ops = &smdk_wm8580_pcm_ops,
},
+};
IIRC the PCM DAI is connected to Secondary i/f of WM8580 on some SMDKs. Isn't it smdk6410 ?
Yes, Your remember is right. SMDK6410 has WM8580 PCM DAI. But, In this time, I couldn't test on SMDK6410. After testing on SMDK6410, I will submit related patch.
Thanks and regards, SB Kim
participants (3)
-
Jassi Brar
-
Mark Brown
-
Sangbeom Kim