summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx28
diff options
context:
space:
mode:
authorLionel Xu <Lionel.Xu@freescale.com>2010-03-08 17:54:48 +0800
committerAlejandro Gonzalez <alex.gonzalez@digi.com>2010-05-25 11:17:18 +0200
commitf377b49771326a4b632088faa2267c7385294c60 (patch)
tree33e7f4d6d68af4eea312171f89433bf602f2bf90 /arch/arm/mach-mx28
parentc5d471596d41aa71765f7a4342b8cbcac685c4ad (diff)
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 <r63889@freescale.com> Signed-off-by: Alejandro Gonzalez <alex.gonzalez@digi.com>
Diffstat (limited to 'arch/arm/mach-mx28')
-rw-r--r--arch/arm/mach-mx28/clock.c141
-rw-r--r--arch/arm/mach-mx28/device.c77
-rw-r--r--arch/arm/mach-mx28/mx28evk.c12
-rw-r--r--arch/arm/mach-mx28/mx28evk_pins.c43
4 files changed, 271 insertions, 2 deletions
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 <mach/lcdif.h>
#include <mach/ddi_bc.h>
+#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 <linux/err.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/i2c.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -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)