From f377b49771326a4b632088faa2267c7385294c60 Mon Sep 17 00:00:00 2001 From: Lionel Xu Date: Mon, 8 Mar 2010 17:54:48 +0800 Subject: ENGR00117750 MX28 ALSA:Support audio playback through SAIF Porting from mxc sound asoc driver, to support audio playback on mx28 through saif Signed-off-by: Lionel Xu Signed-off-by: Alejandro Gonzalez --- arch/arm/mach-mx28/clock.c | 141 +++++++++++++++++++++++++++++++++++++- arch/arm/mach-mx28/device.c | 77 +++++++++++++++++++++ arch/arm/mach-mx28/mx28evk.c | 12 ++++ arch/arm/mach-mx28/mx28evk_pins.c | 43 ++++++++++++ 4 files changed, 271 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-mx28') diff --git a/arch/arm/mach-mx28/clock.c b/arch/arm/mach-mx28/clock.c index fd4695e4a7d4..e7ab14dc4213 100644 --- a/arch/arm/mach-mx28/clock.c +++ b/arch/arm/mach-mx28/clock.c @@ -28,7 +28,14 @@ #include "regs-clkctrl.h" #include "regs-digctl.h" - +#define HW_SAIF_CTRL (0x00000000) +#define HW_SAIF_STAT (0x00000010) +#define SAIF0_CTRL (IO_ADDRESS(SAIF0_PHYS_ADDR) + HW_SAIF_CTRL) +#define SAIF0_STAT (IO_ADDRESS(SAIF0_PHYS_ADDR) + HW_SAIF_STAT) +#define SAIF1_CTRL (IO_ADDRESS(SAIF1_PHYS_ADDR) + HW_SAIF_CTRL) +#define SAIF1_STAT (IO_ADDRESS(SAIF1_PHYS_ADDR) + HW_SAIF_STAT) +#define BM_SAIF_CTRL_RUN 0x00000001 +#define BM_SAIF_STAT_BUSY 0x00000001 #define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR) @@ -873,7 +880,7 @@ static int ssp_set_rate(struct clk *clk, unsigned long rate) out: if (ret != 0) - printk(KERN_ERR "%s: error %d\n", __func__, ret); + pr_err("%s: error %d\n", __func__, ret); return ret; } @@ -1217,6 +1224,9 @@ static struct clk gpmi_clk = { }; static unsigned long saif_get_rate(struct clk *clk); +static unsigned long saif_set_rate(struct clk *clk, unsigned int rate); +static unsigned long saif_set_parent(struct clk *clk, struct clk *parent); + static struct clk saif_clk[] = { { .parent = &pll_clk[0], @@ -1225,6 +1235,14 @@ static struct clk saif_clk[] = { .disable = mx28_raw_disable, .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0, .enable_bits = BM_CLKCTRL_SAIF0_CLKGATE, + .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0, + .scale_bits = 0, + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0, + .busy_bits = 29, + .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, + .bypass_bits = 0, + .set_rate = saif_set_rate, + .set_parent = saif_set_parent, }, { .parent = &pll_clk[0], @@ -1233,6 +1251,14 @@ static struct clk saif_clk[] = { .disable = mx28_raw_disable, .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1, .enable_bits = BM_CLKCTRL_SAIF1_CLKGATE, + .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1, + .scale_bits = 0, + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1, + .busy_bits = 29, + .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, + .bypass_bits = 1, + .set_rate = saif_set_rate, + .set_parent = saif_set_parent, }, }; @@ -1253,6 +1279,109 @@ static unsigned long saif_get_rate(struct clk *clk) return (clk->parent->get_rate(clk->parent) / 0x10000) * div; } +static unsigned long saif_set_rate(struct clk *clk, unsigned int rate) +{ + u16 div = 0; + u32 clkctrl_saif; + u64 rates; + struct clk *parent = clk->parent; + + pr_debug("%s: rate %d, parent rate %d\n", __func__, rate, + clk_get_rate(parent)); + + if (rate > clk_get_rate(parent)) + return -EINVAL; + /*saif clock always use frac div*/ + rates = 65536 * (u64)rate; + rates = rates + (u64)(clk_get_rate(parent) / 2); + do_div(rates, clk_get_rate(parent)); + div = rates; + + pr_debug("%s: div calculated is %d\n", __func__, div); + if (!div) + return -EINVAL; + + clkctrl_saif = __raw_readl(clk->scale_reg); + clkctrl_saif &= ~BM_CLKCTRL_SAIF0_DIV_FRAC_EN; + clkctrl_saif &= ~BM_CLKCTRL_SAIF0_DIV; + clkctrl_saif |= div; + clkctrl_saif |= BM_CLKCTRL_SAIF0_DIV_FRAC_EN; + clkctrl_saif &= ~BM_CLKCTRL_SAIF0_CLKGATE; + __raw_writel(clkctrl_saif, clk->scale_reg); + if (clk->busy_reg) { + int i; + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) { + pr_err("couldn't set up SAIF clk divisor\n"); + return -ETIMEDOUT; + } + } + return 0; +} + +static unsigned long saif_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -EINVAL; + int shift = 4; + /*bypass*/ + if (parent == &pll_clk[0]) + shift = 8; + if (clk->bypass_reg) { + __raw_writel(1 << clk->bypass_bits, clk->bypass_reg + shift); + ret = 0; + } + return ret; +} + +static int saif_mclk_enable(struct clk *clk) +{ + /*Check if enabled already*/ + if (__raw_readl(clk->busy_reg) & clk->busy_bits) + return 0; + /*Enable saif to enable mclk*/ + __raw_writel(0x1, clk->enable_reg); + mdelay(1); + __raw_writel(0x1, clk->enable_reg); + mdelay(1); + return 0; +} + +static int saif_mclk_disable(struct clk *clk) +{ + /*Check if disabled already*/ + if (!(__raw_readl(clk->busy_reg) & clk->busy_bits)) + return 0; + /*Disable saif to disable mclk*/ + __raw_writel(0x0, clk->enable_reg); + mdelay(1); + __raw_writel(0x0, clk->enable_reg); + mdelay(1); + return 0; +} + +static struct clk saif_mclk[] = { + { + .parent = &saif_clk[0], + .enable = saif_mclk_enable, + .disable = saif_mclk_disable, + .enable_reg = SAIF0_CTRL, + .enable_bits = BM_SAIF_CTRL_RUN, + .busy_reg = SAIF0_STAT, + .busy_bits = BM_SAIF_STAT_BUSY, + }, + { + .parent = &saif_clk[1], + .enable = saif_mclk_enable, + .disable = saif_mclk_disable, + .enable_reg = SAIF1_CTRL, + .enable_bits = BM_SAIF_CTRL_RUN, + .busy_reg = SAIF1_STAT, + .busy_bits = BM_SAIF_STAT_BUSY, + }, +}; + static unsigned long pcmspdif_get_rate(struct clk *clk) { return clk->parent->get_rate(clk->parent) / 4; @@ -1456,6 +1585,14 @@ static struct clk_lookup onchip_clocks[] = { .con_id = "fec_clk", .clk = &enet_out_clk, }, + { + .con_id = "saif_mclk.0", + .clk = &saif_mclk[0], + }, + { + .con_id = "saif_mclk.1", + .clk = &saif_mclk[1], + } }; static void mx28_clock_scan(void) diff --git a/arch/arm/mach-mx28/device.c b/arch/arm/mach-mx28/device.c index e1e447e77538..4e07d5261cd3 100644 --- a/arch/arm/mach-mx28/device.c +++ b/arch/arm/mach-mx28/device.c @@ -40,6 +40,7 @@ #include #include +#include "regs-digctl.h" #include "device.h" #include "mx28_pins.h" @@ -1004,6 +1005,81 @@ static void __init mx28_init_dcp(void) } #endif +#if defined(CONFIG_SND_MXS_SOC_DAI) || defined(CONFIG_SND_MXS_SOC_DAI_MODULE) +static int audio_clk_init(void) +{ + struct clk *saif_clk; + struct clk *pll_clk; + int ret = -EINVAL; + saif_clk = clk_get(NULL, "saif.0"); + if (IS_ERR(saif_clk)) { + pr_err("%s:failed to get saif_clk\n", __func__); + goto err_clk_init; + } + pll_clk = clk_get(NULL, "pll.0"); + if (IS_ERR(pll_clk)) { + pr_err("%s:failed to get pll_clk\n", __func__); + goto err_clk_init; + } + ret = clk_set_parent(saif_clk, pll_clk); + if (ret) { + pr_err("%s:failed to set parent clk\n", __func__); + goto err_clk_init; + } + ret = 0; + /*set a default freq 12M to sgtl5000*/ + clk_set_rate(saif_clk, 12000000); + clk_enable(saif_clk); + /*set the saif clk mux*/ + __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0), \ + IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL); +err_clk_init: + return ret; +} + +static int audio_clk_finit(void) +{ + struct clk *saif_clk; + int ret = 0; + saif_clk = clk_get(NULL, "saif.0"); + if (IS_ERR(saif_clk)) { + pr_err("%s:failed to get saif_clk\n", __func__); + ret = -EINVAL; + goto err_clk_finit; + } + clk_disable(saif_clk); +err_clk_finit: + return ret; +} + +static struct mxs_audio_platform_data audio_plat_data = { +#if defined(CONFIG_SND_MXS_SOC_SAIF0_SELECT) + .saif0_select = 1, +#endif +#if defined(CONFIG_SND_MXS_SOC_SAIF1_SELECT) + .saif1_select = 1, +#endif + .init = audio_clk_init, + .finit = audio_clk_finit, +}; +#endif + +#if defined(CONFIG_SND_SOC_SGTL5000) || defined(CONFIG_SND_SOC_SGTL5000_MODULE) +void __init mx28_init_audio(void) +{ struct platform_device *pdev; + pdev = mxs_get_device("mxs-sgtl5000", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + mxs_add_device(pdev, 3); + pdev->dev.platform_data = &audio_plat_data; +} +#else +void __init mx28_init_audio(void) +{ +} +#endif + + int __init mx28_device_init(void) { mx28_init_dma(); @@ -1018,6 +1094,7 @@ int __init mx28_device_init(void) mx28_init_flexcan(); mx28_init_kbd(); mx28_init_ts(); + mx28_init_audio(); mx28_init_lcdif(); mx28_init_pxp(); mx28_init_dcp(); diff --git a/arch/arm/mach-mx28/mx28evk.c b/arch/arm/mach-mx28/mx28evk.c index a449571a134c..c3254e3c3c87 100644 --- a/arch/arm/mach-mx28/mx28evk.c +++ b/arch/arm/mach-mx28/mx28evk.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,16 @@ #include "device.h" #include "mx28evk.h" +static struct i2c_board_info __initdata mxs_i2c_device[] = { + { I2C_BOARD_INFO("sgtl5000-i2c", 0x14), .flags = I2C_M_TEN } +}; + +static void i2c_device_init(void) +{ + mxs_i2c_device[0].platform_data = (void *)clk_get(NULL, "saif_mclk.0"); + i2c_register_board_info(0, mxs_i2c_device, ARRAY_SIZE(mxs_i2c_device)); +} + static void __init fixup_board(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { @@ -86,6 +97,7 @@ static void __init mx28evk_init_leds(void) static void __init mx28evk_device_init(void) { /* Add mx28evk special code */ + i2c_device_init(); mx28evk_init_leds(); } diff --git a/arch/arm/mach-mx28/mx28evk_pins.c b/arch/arm/mach-mx28/mx28evk_pins.c index faefa6177dc9..8bddbeb9f9e5 100644 --- a/arch/arm/mach-mx28/mx28evk_pins.c +++ b/arch/arm/mach-mx28/mx28evk_pins.c @@ -748,6 +748,49 @@ static struct pin_desc mx28evk_fixed_pins[] = { .pull = 1, }, #endif +#if defined(CONFIG_SND_MXS_SOC_DAI) || defined(CONFIG_SND_MXS_SOC_DAI_MODULE) + /* Configurations of SAIF0 port pins */ + { + .name = "SAIF0_MCLK", + .id = PINID_SAIF0_MCLK, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF0_LRCLK", + .id = PINID_SAIF0_LRCLK, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF0_BITCLK", + .id = PINID_SAIF0_BITCLK, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF0_SDATA0", + .id = PINID_SAIF0_SDATA0, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, +#endif }; #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) -- cgit v1.2.3