summaryrefslogtreecommitdiff
path: root/arch/arm/plat-stmp3xxx
diff options
context:
space:
mode:
authorRob Herring <r.herring@freescale.com>2009-10-19 14:43:19 -0500
committerRob Herring <r.herring@freescale.com>2009-10-26 16:57:04 -0500
commit460b55880e47a98943f5072bc03ffcfcc8a40a14 (patch)
tree5690552665f0b7843e6552e4d5fe7b63cbc78f51 /arch/arm/plat-stmp3xxx
parent40abba66d676c6c7aff57a5fbd1345974c90b2fe (diff)
ENGR00117389 Port 5.0.0 release to 2.6.31
This is i.MX BSP 5.0.0 release ported to 2.6.31 Signed-off-by: Rob Herring <r.herring@freescale.com> Signed-off-by: Alan Tull <r80115@freescale.com> Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
Diffstat (limited to 'arch/arm/plat-stmp3xxx')
-rw-r--r--arch/arm/plat-stmp3xxx/Kconfig2
-rw-r--r--arch/arm/plat-stmp3xxx/Makefile16
-rw-r--r--arch/arm/plat-stmp3xxx/clock.c138
-rw-r--r--arch/arm/plat-stmp3xxx/clock.h17
-rw-r--r--arch/arm/plat-stmp3xxx/core.c20
-rw-r--r--arch/arm/plat-stmp3xxx/cpufreq.c475
-rw-r--r--arch/arm/plat-stmp3xxx/dcp-bootstream.c303
-rw-r--r--arch/arm/plat-stmp3xxx/devices.c159
-rw-r--r--arch/arm/plat-stmp3xxx/dma.c45
-rw-r--r--arch/arm/plat-stmp3xxx/gpmi.c40
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/arc_otg.h97
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/dcp_bootstream_ioctl.h32
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/fsl_usb.h60
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/fsl_usb_gadget.h40
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/gpmi.h24
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/lradc.h60
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/memory.h41
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/mmc.h17
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/ocram-malloc.h26
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pinmux.h5
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pins.h30
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/power.h67
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pwm-led.h25
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/regulator.h23
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/rotdec.h25
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h54
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/unique-id.h30
-rw-r--r--arch/arm/plat-stmp3xxx/lradc.c332
-rw-r--r--arch/arm/plat-stmp3xxx/mmc.c148
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c2
-rw-r--r--arch/arm/plat-stmp3xxx/power-test.c213
-rw-r--r--arch/arm/plat-stmp3xxx/rotdec.c39
-rw-r--r--arch/arm/plat-stmp3xxx/spi.c106
-rw-r--r--arch/arm/plat-stmp3xxx/unique-id.c198
34 files changed, 2842 insertions, 67 deletions
diff --git a/arch/arm/plat-stmp3xxx/Kconfig b/arch/arm/plat-stmp3xxx/Kconfig
index 2cf37c35951b..e211f2604307 100644
--- a/arch/arm/plat-stmp3xxx/Kconfig
+++ b/arch/arm/plat-stmp3xxx/Kconfig
@@ -32,6 +32,8 @@ config MACH_STMP378X
endchoice
+source arch/arm/mach-stmp378x/Kconfig
+
endmenu
endif
diff --git a/arch/arm/plat-stmp3xxx/Makefile b/arch/arm/plat-stmp3xxx/Makefile
index 31dd518f37a5..50114dca7261 100644
--- a/arch/arm/plat-stmp3xxx/Makefile
+++ b/arch/arm/plat-stmp3xxx/Makefile
@@ -2,4 +2,18 @@
# Makefile for the linux kernel.
#
# Object file lists.
-obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o devices.o
+obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o devices.o \
+ lradc.o spi.o mmc.o \
+ power-test.o
+
+obj-$(CONFIG_ARCH_STMP378X) += dcp-bootstream.o
+
+# Power Management
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+
+obj-$(CONFIG_STMP3XXX_UNIQUE_ID) += unique-id.o
+
+# charging/current limitation testing
+obj-m += power-test.o
+
+
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
index 5d2f19a09e44..b59ffbb2debe 100644
--- a/arch/arm/plat-stmp3xxx/clock.c
+++ b/arch/arm/plat-stmp3xxx/clock.c
@@ -421,6 +421,83 @@ static long cpu_round_rate(struct clk *clk, u32 rate)
return r;
}
+static int emi_set_rate(struct clk *clk, u32 rate)
+{
+ int ret = 0;
+
+ if (rate < 24000)
+ return -EINVAL;
+ else {
+ int i;
+ struct stmp3xxx_emi_scaling_data sc_data;
+ int (*scale)(struct stmp3xxx_emi_scaling_data *) =
+ (void *)STMP3XXX_OCRAM_BASE;
+ void *saved_ocram;
+ u32 clkctrl_emi;
+ u32 clkctrl_frac;
+ int div = 1;
+ /*
+ * We've been setting div to HW_CLKCTRL_CPU_RD() & 0x3f so far.
+ * TODO: verify 1 is still valid.
+ */
+
+ if (!stmp3xxx_ram_funcs_sz)
+ goto out;
+
+ for (clkctrl_emi = div; clkctrl_emi < 0x3f;
+ clkctrl_emi += div) {
+ clkctrl_frac =
+ (pll_clk.rate * 18 + rate * clkctrl_emi / 2) /
+ (rate * clkctrl_emi);
+ if (clkctrl_frac >= 18 && clkctrl_frac <= 35) {
+ pr_debug("%s: clkctrl_frac found %d for %d\n",
+ __func__, clkctrl_frac, clkctrl_emi);
+ if (pll_clk.rate * 18 /
+ clkctrl_frac / clkctrl_emi / 100 ==
+ rate / 100)
+ break;
+ }
+ }
+ if (clkctrl_emi >= 0x3f)
+ return -EINVAL;
+ pr_debug("%s: clkctrl_emi %d, clkctrl_frac %d\n",
+ __func__, clkctrl_emi, clkctrl_frac);
+
+ saved_ocram = kmalloc(stmp3xxx_ram_funcs_sz, GFP_KERNEL);
+ if (!saved_ocram)
+ return -ENOMEM;
+ memcpy(saved_ocram, scale, stmp3xxx_ram_funcs_sz);
+ memcpy(scale, stmp3xxx_ram_freq_scale, stmp3xxx_ram_funcs_sz);
+
+ sc_data.emi_div = clkctrl_emi;
+ sc_data.frac_div = clkctrl_frac;
+ sc_data.cur_freq = clk->rate / 1000;
+ sc_data.new_freq = rate / 1000;
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ scale(&sc_data);
+
+ local_fiq_enable();
+ local_irq_enable();
+
+ for (i = 10000; i; i--)
+ if (!clk_is_busy(clk))
+ break;
+ memcpy(scale, saved_ocram, stmp3xxx_ram_funcs_sz);
+ kfree(saved_ocram);
+
+ if (!i) {
+ printk(KERN_ERR "couldn't set up EMI divisor\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
static long emi_get_rate(struct clk *clk)
{
long rate = clk->parent->rate * 18;
@@ -652,6 +729,8 @@ static struct clk_ops lcdif_ops = {
static struct clk_ops emi_ops = {
.get_rate = emi_get_rate,
+ .set_rate = emi_set_rate,
+ .set_parent = clkseq_set_parent,
};
/* List of on-chip clocks */
@@ -860,6 +939,50 @@ static struct clk usb_clk = {
.ops = &min_ops,
};
+static struct clk vid_clk = {
+ .parent = &osc_24M,
+#ifdef CONFIG_MACH_STMP378X
+ .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC1,
+ .enable_shift = 31,
+ .enable_negate = 1,
+#endif
+ .flags = RATE_PROPAGATES,
+ .ops = &min_ops,
+};
+
+static struct clk clk_tv108M_ng = {
+ .parent = &vid_clk,
+#ifdef CONFIG_MACH_STMP378X
+ .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_TV,
+ .enable_shift = 31,
+ .enable_negate = 1,
+#endif
+ .flags = FIXED_RATE,
+ .ops = &min_ops,
+};
+
+static struct clk clk_tv54M = {
+ .parent = &vid_clk,
+#ifdef CONFIG_MACH_STMP378X
+ .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_TV,
+ .enable_shift = 30,
+ .enable_negate = 1,
+#endif
+ .flags = FIXED_RATE,
+ .ops = &min_ops,
+};
+
+static struct clk clk_tv27M = {
+ .parent = &vid_clk,
+#ifdef CONFIG_MACH_STMP378X
+ .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_TV,
+ .enable_shift = 30,
+ .enable_negate = 1,
+#endif
+ .flags = FIXED_RATE,
+ .ops = &min_ops,
+};
+
/* list of all the clocks */
static struct clk_lookup onchip_clks[] = {
{
@@ -922,6 +1045,21 @@ static struct clk_lookup onchip_clks[] = {
}, {
.con_id = "usb",
.clk = &usb_clk,
+ }, {
+ .con_id = "ref_vid",
+ .clk = &vid_clk,
+ }, {
+ .con_id = "tv108M_ng",
+ .clk = &clk_tv108M_ng,
+ }, {
+ .con_id = "tv54M",
+ .clk = &clk_tv54M,
+ }, {
+ .con_id = "tv27M",
+ .clk = &clk_tv27M,
+ }, {
+ .con_id = "saif",
+ .clk = &saif_clk,
},
};
diff --git a/arch/arm/plat-stmp3xxx/clock.h b/arch/arm/plat-stmp3xxx/clock.h
index a6611e1a3510..1008cb0c8a7a 100644
--- a/arch/arm/plat-stmp3xxx/clock.h
+++ b/arch/arm/plat-stmp3xxx/clock.h
@@ -48,6 +48,23 @@ struct clk {
struct clk_ops *ops;
};
+struct stmp3xxx_emi_scaling_data {
+ u32 emi_div;
+ u32 frac_div;
+ u32 cur_freq;
+ u32 new_freq;
+};
+
+#ifdef CONFIG_STMP378X_RAM_FREQ_SCALING
+extern void stmp3xxx_ram_freq_scale(struct stmp3xxx_emi_scaling_data *);
+extern u32 stmp3xxx_ram_funcs_sz;
+#else
+static inline void stmp3xxx_ram_freq_scale(struct stmp3xxx_emi_scaling_data *p)
+{
+}
+static u32 stmp3xxx_ram_funcs_sz;
+#endif
+
#endif /* __ASSEMBLER__ */
/* Flags */
diff --git a/arch/arm/plat-stmp3xxx/core.c b/arch/arm/plat-stmp3xxx/core.c
index 37b8a09148a4..6ada910d18c0 100644
--- a/arch/arm/plat-stmp3xxx/core.c
+++ b/arch/arm/plat-stmp3xxx/core.c
@@ -23,6 +23,8 @@
#include <mach/platform.h>
#include <mach/dma.h>
#include <mach/regs-clkctrl.h>
+#include <mach/regs-rtc.h>
+#include <mach/system.h>
static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
{
@@ -114,15 +116,25 @@ int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
}
EXPORT_SYMBOL(stmp3xxx_reset_block);
-struct platform_device stmp3xxx_dbguart = {
- .name = "stmp3xxx-dbguart",
- .id = -1,
-};
+static void stmp3xxx_machine_restart(char mode, const char *cmd)
+{
+ arch_reset(mode, cmd);
+ printk(KERN_ERR"stmp3xxx_machine_restart failed -- System halted\n");
+ for (;;)
+ continue;
+}
void __init stmp3xxx_init(void)
{
/* Turn off auto-slow and other tricks */
stmp3xxx_clearl(0x7f00000, REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
+ /* Re-route machine restart to our own handler */
+ arm_pm_restart = stmp3xxx_machine_restart;
+
stmp3xxx_dma_init();
+
+ stmp3xxx_setl(BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP |
+ BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0);
}
diff --git a/arch/arm/plat-stmp3xxx/cpufreq.c b/arch/arm/plat-stmp3xxx/cpufreq.c
new file mode 100644
index 000000000000..aa83d33bc64c
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/cpufreq.c
@@ -0,0 +1,475 @@
+/*
+ * CPU frequency scaling for Freescale STMP37XX/STMP378X
+ *
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/* #define DEBUG */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+//#include <linux/regulator/regulator-drv.h>
+#include <linux/notifier.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <mach/regulator.h>
+#include <mach/power.h>
+#include <mach/regs-digctl.h>
+#include <mach/regs-clkctrl.h>
+#include <mach/platform.h>
+
+#define VERY_HI_RATE 2000000000
+#define CLKCTRL_PLL_PWD_BIT 16
+#define CLKCTRL_PLL_BYPASS 0x1ff
+
+static struct profile {
+ int cpu;
+ int ahb;
+ int emi;
+ int ss;
+ int vddd;
+ int vddd_bo;
+ int cur;
+ int vddio;
+ int vdda;
+ int pll_off;
+} profiles[] = {
+ { 24000, 24000, 24000, 3, 1000000,
+ 925000, 150000, 3075000, 1725000, 1 },
+ { 64000, 64000, 48000, 3, 1000000,
+ 925000, 150000, 3300000, 1750000, 0 },
+ { 261820, 130910, 130910, 0, 1225000,
+ 1125000, 173000, 3300000, 1750000, 0 },
+ { 360000, 120000, 120000, 0, 1350000,
+ 1250000, 200000, 3300000, 1750000, 0 },
+ { 392730, 130910, 130910, 0, 1400000,
+ 1300000, 225000, 3300000, 1750000, 0 },
+ { 454740, 151580, 151580, 0, 1550000,
+ 1450000, 355000, 3300000, 1750000, 0 },
+};
+
+static struct stmp3xxx_cpufreq {
+ struct cpufreq_policy policy;
+ struct regulator *regulator;
+ struct notifier_block nb;
+ struct notifier_block init_nb;
+ int freq_id;
+ int next_freq_id;
+ spinlock_t lock;
+} cpufreq_bdata;
+
+static u32 clkseq_setting;
+
+static int reg_callback(struct notifier_block *, unsigned long, void *);
+static int init_reg_callback(struct notifier_block *, unsigned long, void *);
+
+static inline void __set_new_policy(struct cpufreq_policy *policy)
+{
+ spin_lock(&cpufreq_bdata.lock);
+
+ if (policy)
+ cpufreq_bdata.policy = *policy;
+ else
+ memset(&cpufreq_bdata.policy, 0, sizeof(cpufreq_bdata.policy));
+
+ if (cpufreq_bdata.regulator)
+ goto out;
+
+ cpufreq_bdata.regulator = regulator_get(NULL, "cpufreq-1");
+ if (!cpufreq_bdata.regulator || IS_ERR(cpufreq_bdata.regulator))
+ cpufreq_bdata.regulator = NULL;
+ else {
+ regulator_set_mode(cpufreq_bdata.regulator,
+ REGULATOR_MODE_FAST);
+ if (cpufreq_bdata.regulator)
+ regulator_register_notifier(
+ cpufreq_bdata.regulator,
+ &cpufreq_bdata.nb);
+ }
+
+out:
+ spin_unlock(&cpufreq_bdata.lock);
+}
+
+static int stmp3xxx_verify_speed(struct cpufreq_policy *policy)
+{
+ struct clk *cpu_clk;
+
+ pr_debug("%s: entered, policy %p\n", __func__, policy);
+
+ __set_new_policy(policy);
+
+ if (policy->cpu)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ cpu_clk = clk_get(NULL, "cpu");
+ if (IS_ERR(cpu_clk))
+ return PTR_ERR(cpu_clk);
+
+ pr_debug("%s: policy->min %d, policy->max %d\n",
+ __func__, policy->min, policy->max);
+ policy->min = clk_round_rate(cpu_clk, policy->min);
+ policy->max = clk_round_rate(cpu_clk, policy->max);
+ pr_debug("%s: after rounding rate: policy->min %d, policy->max %d\n",
+ __func__, policy->min, policy->max);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ clk_put(cpu_clk);
+
+ return 0;
+}
+
+static unsigned int stmp3xxx_getspeed(unsigned int cpu)
+{
+ struct clk *cpu_clk;
+ unsigned long rate;
+
+ pr_debug("%s: entered\n", __func__);
+ if (cpu)
+ return 0;
+
+ cpu_clk = clk_get(NULL, "cpu");
+ if (IS_ERR(cpu_clk))
+ return 0;
+ rate = clk_get_rate(cpu_clk);
+ pr_debug("%s: got cpu speed %ld\n", __func__, rate);
+ clk_put(cpu_clk);
+
+ return rate;
+}
+
+static int set_op(unsigned int target_freq)
+{
+ struct clk *cpu_clk, *ahb_clk, *emi_clk;
+ struct regulator *vddd, *vdddbo, *cur_limit, *vddio, *vdda;
+ struct cpufreq_freqs freqs;
+ int ret = 0, i;
+
+ cur_limit = cpufreq_bdata.regulator;
+ pr_debug("%s: entered\n", __func__);
+ cpu_clk = clk_get(NULL, "cpu");
+ if (IS_ERR(cpu_clk)) {
+ ret = PTR_ERR(cpu_clk);
+ goto out_cpu;
+ }
+ ahb_clk = clk_get(NULL, "hclk");
+ if (IS_ERR(ahb_clk)) {
+ ret = PTR_ERR(ahb_clk);
+ goto out_ahb;
+ }
+ emi_clk = clk_get(NULL, "emi");
+ if (IS_ERR(emi_clk)) {
+ ret = PTR_ERR(emi_clk);
+ goto out_emi;
+ }
+
+ vddd = regulator_get(NULL, "vddd");
+ vdddbo = regulator_get(NULL, "vddd_bo");
+ if (IS_ERR(vdddbo))
+ vdddbo = NULL;
+ vddio = regulator_get(NULL, "vddio");
+ if (IS_ERR(vddio)) {
+ vddio = NULL;
+ pr_warning("unable to get vddio");
+ }
+ vdda = regulator_get(NULL, "vdda");
+ if (IS_ERR(vdda)) {
+ vdda = NULL;
+ pr_warning("unable to get vddio");
+ }
+
+ freqs.old = clk_get_rate(cpu_clk);
+ freqs.cpu = 0;
+ for (i = 0; i < ARRAY_SIZE(profiles) - 1; i++) {
+ if (profiles[i].cpu <= target_freq &&
+ target_freq < profiles[i + 1].cpu) {
+ freqs.new = profiles[i].cpu;
+ cpufreq_bdata.next_freq_id = i;
+ break;
+ }
+ if (!vddd && profiles[i].cpu > freqs.old) {
+ /* can't safely set more than now */
+ freqs.new = profiles[i - 1].cpu;
+ break;
+ }
+ }
+
+ pr_debug("target_freq %d, new %d\n", target_freq, freqs.new);
+ if (i == ARRAY_SIZE(profiles) - 1) {
+ freqs.new = profiles[i].cpu;
+ cpufreq_bdata.next_freq_id = i;
+ }
+
+ if (IS_ERR(vddd)) {
+ ret = PTR_ERR(vddd);
+ if (!cpufreq_bdata.init_nb.notifier_call) {
+ /* we only register once */
+ cpufreq_bdata.init_nb.notifier_call = init_reg_callback;
+ bus_register_notifier(&platform_bus_type,
+ &cpufreq_bdata.init_nb);
+ }
+ goto out_vddd;
+ }
+
+ pr_debug("i %d: freqs.old %d, freqs.new %d\n",
+ i, freqs.old, freqs.new);
+
+ spin_lock(&cpufreq_bdata.lock);
+
+ if (freqs.old == 24000 && freqs.new > 24000) {
+ /* turn pll on */
+ stmp3xxx_setl(CLKCTRL_PLL_PWD_BIT, REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0);
+ udelay(10);
+ } else if (freqs.old > 24000 && freqs.new == 24000)
+ clkseq_setting = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+
+ if (cur_limit && (freqs.old < freqs.new)) {
+ ret = regulator_set_current_limit(cur_limit, profiles[i].cur, profiles[i].cur);
+ if (ret)
+ goto out_cur;
+ }
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ if (freqs.old > freqs.new) {
+ int ss = profiles[i].ss;
+ clk_set_rate(cpu_clk, profiles[i].cpu);
+ clk_set_rate(ahb_clk, profiles[i].ahb);
+ clk_set_rate(emi_clk, profiles[i].emi);
+ __raw_writel(BF(ss, DIGCTL_ARMCACHE_VALID_SS) |
+ BF(ss, DIGCTL_ARMCACHE_DRTY_SS) |
+ BF(ss, DIGCTL_ARMCACHE_CACHE_SS) |
+ BF(ss, DIGCTL_ARMCACHE_DTAG_SS) |
+ BF(ss, DIGCTL_ARMCACHE_ITAG_SS), REGS_DIGCTL_BASE + HW_DIGCTL_ARMCACHE);
+ if (vddd && vdddbo && vddio && vdda) {
+ ret = regulator_set_voltage(vddd, profiles[i].vddd, profiles[i].vddd);
+ if (ret)
+ ret = regulator_set_voltage(vddd,
+ profiles[i].vddd,
+ profiles[i].vddd);
+ regulator_set_voltage(vdddbo, profiles[i].vddd_bo, profiles[i].vddd_bo);
+
+ ret = regulator_set_voltage(vddio, profiles[i].vddio,
+ profiles[i].vddio);
+ if (ret)
+ ret = regulator_set_voltage(vddio,
+ profiles[i].vddio,
+ profiles[i].vddio);
+ ret = regulator_set_voltage(vdda, profiles[i].vdda,
+ profiles[i].vdda);
+ if (ret)
+ ret = regulator_set_voltage(vdda,
+ profiles[i].vdda,
+ profiles[i].vdda);
+ }
+ } else {
+ int ss = profiles[i].ss;
+ if (vddd && vdddbo && vddio && vdda) {
+ ret = regulator_set_voltage(vddd, profiles[i].vddd, profiles[i].vddd);
+ if (ret)
+ ret = regulator_set_voltage(vddd,
+ profiles[i].vddd,
+ profiles[i].vddd);
+ regulator_set_voltage(vdddbo, profiles[i].vddd_bo, profiles[i].vddd_bo);
+ ret = regulator_set_voltage(vddio, profiles[i].vddio,
+ profiles[i].vddio);
+ if (ret)
+ ret = regulator_set_voltage(vddio,
+ profiles[i].vddio,
+ profiles[i].vddio);
+ ret = regulator_set_voltage(vdda, profiles[i].vdda,
+ profiles[i].vdda);
+ if (ret)
+ ret = regulator_set_voltage(vdda,
+ profiles[i].vdda,
+ profiles[i].vdda);
+ }
+ __raw_writel(BF(ss, DIGCTL_ARMCACHE_VALID_SS) |
+ BF(ss, DIGCTL_ARMCACHE_DRTY_SS) |
+ BF(ss, DIGCTL_ARMCACHE_CACHE_SS) |
+ BF(ss, DIGCTL_ARMCACHE_DTAG_SS) |
+ BF(ss, DIGCTL_ARMCACHE_ITAG_SS), REGS_DIGCTL_BASE + HW_DIGCTL_ARMCACHE);
+ clk_set_rate(cpu_clk, profiles[i].cpu);
+ clk_set_rate(ahb_clk, profiles[i].ahb);
+ clk_set_rate(emi_clk, profiles[i].emi);
+ }
+ udelay(100);
+
+ if (freqs.old > 24000 && freqs.new == 24000) {
+ /* turn pll off */
+ stmp3xxx_clearl(CLKCTRL_PLL_PWD_BIT, REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0);
+ __raw_writel(CLKCTRL_PLL_BYPASS, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+ } else if (freqs.old == 24000 && freqs.new > 24000)
+ __raw_writel(clkseq_setting, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ if (cur_limit && (freqs.old > freqs.new)) /* will not fail */
+ regulator_set_current_limit(cur_limit, profiles[i].cur, profiles[i].cur);
+
+ cpufreq_bdata.freq_id = i;
+
+out_cur:
+ spin_unlock(&cpufreq_bdata.lock);
+ if (vddd)
+ regulator_put(vddd);
+ if (vddio)
+ regulator_put(vddio);
+ if (vdda)
+ regulator_put(vdda);
+out_vddd:
+ clk_put(emi_clk);
+out_emi:
+ clk_put(ahb_clk);
+out_ahb:
+ clk_put(cpu_clk);
+out_cpu:
+
+ return ret;
+}
+
+static int stmp3xxx_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ return set_op(target_freq);
+}
+
+static int reg_callback(struct notifier_block *self, unsigned long event,
+ void *data)
+{
+ struct stmp3xxx_cpufreq *_temp =
+ container_of(self, struct stmp3xxx_cpufreq, nb);
+ struct cpufreq_policy *policy = &_temp->policy;
+ int max_prof = ARRAY_SIZE(profiles) - 1;
+ int ret = -EINVAL;
+
+ pr_debug("%s: entered, _temp %p, policy %p, cpu %d, freq_id %d\n",
+ __func__, _temp, policy, policy->cpu, _temp->freq_id);
+
+ if (policy)
+ policy = cpufreq_cpu_get(policy->cpu);
+ if (!policy) {
+ printk(KERN_ERR "%s: couldn't get cpufreq policy\n", __func__);
+ goto out;
+ }
+
+ /* FIXME: Need a lock: set policy by user VS async USB event */
+ switch (event) {
+ case STMP3XXX_REG5V_IS_USB:
+ pr_debug("%s: limiting max_freq to %d\n", __func__,
+ profiles[max_prof - 1].cpu);
+ policy->user_policy.min = profiles[0].cpu;
+ policy->user_policy.max = profiles[max_prof - 1].cpu;
+ if (_temp->freq_id > max_prof - 1)
+ set_op(profiles[max_prof - 1].cpu);
+ break;
+
+ case STMP3XXX_REG5V_NOT_USB:
+ pr_debug("%s: undo limiting max_freq to %d\n", __func__,
+ profiles[max_prof - 1].cpu);
+ policy->user_policy.min = profiles[0].cpu;
+ policy->user_policy.max = profiles[max_prof].cpu;
+ break;
+
+ default:
+ pr_info("%s: unknown event %ld\n", __func__, event);
+ break;
+ }
+ cpufreq_cpu_put(policy);
+ ret = cpufreq_update_policy(policy->cpu);
+out:
+ return ret;
+}
+
+static int init_reg_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ int ret;
+ struct stmp3xxx_cpufreq *_temp =
+ container_of(self, struct stmp3xxx_cpufreq, init_nb);
+
+ ret = set_op(profiles[_temp->next_freq_id].cpu);
+ if (ret == 0)
+ bus_unregister_notifier(&platform_bus_type,
+ &cpufreq_bdata.init_nb);
+ return ret;
+}
+
+static int __init stmp3xxx_cpu_init(struct cpufreq_policy *policy)
+{
+ struct clk *cpu_clk = clk_get(NULL, "cpu");
+
+ pr_debug("%s: entered\n", __func__);
+ if (IS_ERR(cpu_clk))
+ return PTR_ERR(cpu_clk);
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = policy->min = policy->max = clk_get_rate(cpu_clk);
+
+ pr_debug("got CPU clock rate %d\n", policy->cur);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ policy->cpuinfo.min_freq = profiles[0].cpu;
+ policy->cpuinfo.max_freq = profiles[ARRAY_SIZE(profiles) - 1].cpu;
+ policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
+ clk_put(cpu_clk);
+
+ return 0;
+}
+
+static struct cpufreq_driver stmp3xxx_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = stmp3xxx_verify_speed,
+ .target = stmp3xxx_target,
+ .get = stmp3xxx_getspeed,
+ .init = stmp3xxx_cpu_init,
+ .name = "stmp3xxx",
+};
+
+static int __init stmp3xxx_cpufreq_init(void)
+{
+ spin_lock_init(&cpufreq_bdata.lock);
+ cpufreq_bdata.nb.notifier_call = reg_callback;
+ return cpufreq_register_driver(&stmp3xxx_driver);
+}
+
+static int __init stmp3xxx_reg_init(void)
+{
+ pr_debug("%s: enter\n", __func__);
+ if (!cpufreq_bdata.regulator)
+ __set_new_policy(&cpufreq_bdata.policy);
+
+ if (cpufreq_bdata.regulator)
+ regulator_set_current_limit(cpufreq_bdata.regulator,
+ profiles[cpufreq_bdata.freq_id].cur,
+ profiles[cpufreq_bdata.freq_id].cur);
+ return 0 ;
+}
+
+arch_initcall(stmp3xxx_cpufreq_init);
+late_initcall(stmp3xxx_reg_init);
diff --git a/arch/arm/plat-stmp3xxx/dcp-bootstream.c b/arch/arm/plat-stmp3xxx/dcp-bootstream.c
new file mode 100644
index 000000000000..133971d77a42
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/dcp-bootstream.c
@@ -0,0 +1,303 @@
+/*
+ * Freescale STMP378X DCP driver for bootstream update. Only handles the OTP KEY
+ * case and can only encrypt/decrypt.
+ *
+ * Author: Pantelis Antoniou <pantelis@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/regs-dcp.h>
+#include <mach/dcp_bootstream_ioctl.h>
+
+/* use this channel (same as the ROM) */
+#define ROM_DCP_CHAN 3
+
+/* Defines the channel mask for the rom dcp channel */
+#define ROM_DCP_CHAN_MASK (1 << ROM_DCP_CHAN)
+
+/* Defines the initialization value for the dcp control register */
+#define DCP_CTRL_INIT \
+ (BM_DCP_CTRL_GATHER_RESIDUAL_WRITES | \
+ BM_DCP_CTRL_ENABLE_CONTEXT_CACHING)
+
+/* Defines the initialization value for the dcp channel control register */
+#define DCP_CHANNELCTRL_INIT \
+ BF(ROM_DCP_CHAN_MASK, DCP_CHANNELCTRL_ENABLE_CHANNEL)
+
+/* DCP work packet 1 value used to calculate CBC-MAC over the image header */
+#define DCP_PKT1_ENCRYPT \
+ (BM_DCP_PACKET1_DECR_SEMAPHORE | \
+ BM_DCP_PACKET1_ENABLE_CIPHER | \
+ BM_DCP_PACKET1_CIPHER_ENCRYPT | \
+ BM_DCP_PACKET1_CIPHER_INIT | \
+ BM_DCP_PACKET1_OTP_KEY)
+
+/* DCP work packet 1 value used to decrypt DEK in key dictionary */
+#define DCP_PKT1_DECRYPT \
+ (BM_DCP_PACKET1_DECR_SEMAPHORE | \
+ BM_DCP_PACKET1_ENABLE_CIPHER | \
+ BM_DCP_PACKET1_CIPHER_INIT | \
+ BM_DCP_PACKET1_OTP_KEY)
+
+/* DCP (decryption) work packet definition */
+struct hw_dcp_packet {
+ uint32_t pNext; /* next dcp work packet address */
+ uint32_t pkt1; /* dcp work packet 1 (control 0) */
+ uint32_t pkt2; /* dcp work packet 2 (control 1) */
+ uint32_t pSrc; /* source buffer address */
+ uint32_t pDst; /* destination buffer address */
+ uint32_t size; /* buffer size in bytes */
+ uint32_t pPayload; /* payload buffer address */
+ uint32_t stat; /* dcp status (written by dcp) */
+};
+
+struct dma_area {
+ struct hw_dcp_packet hw_packet;
+ uint16_t block[16];
+};
+
+struct stmp3xxx_dcp_bootstream_data {
+ struct device *dev;
+ struct dma_area *dma_area;
+ dma_addr_t dma_area_phys;
+};
+
+/* Only one instance allowed, so this is OK */
+static struct stmp3xxx_dcp_bootstream_data *global_dbd;
+
+static int stmp3xxx_dcp_bootstream_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct stmp3xxx_dcp_bootstream_data *dbd = global_dbd;
+ struct dma_area *da = dbd->dma_area;
+ void __user *argp = (void __user *)arg;
+ unsigned long timeout;
+
+ /* be paranoid */
+ if (dbd == NULL)
+ return -EBADF;
+
+ if (cmd != DBS_ENC && cmd != DBS_DEC)
+ return -EINVAL;
+
+ /* copy to (aligned) block */
+ if (copy_from_user(da->block, argp, 16))
+ return -EFAULT;
+
+ /* Soft reset and remove the clock gate */
+ stmp3xxx_setl(BM_DCP_CTRL_SFTRST, REGS_DCP_BASE + HW_DCP_CTRL);
+
+ /* At 24Mhz, it takes no more than 4 clocks (160 ns) Maximum for
+ * the part to reset, reading the register twice should
+ * be sufficient to get 4 clks delay.
+ */
+ __raw_readl(REGS_DCP_BASE + HW_DCP_CTRL);
+ __raw_readl(REGS_DCP_BASE + HW_DCP_CTRL);
+
+ stmp3xxx_clearl(BM_DCP_CTRL_SFTRST | BM_DCP_CTRL_CLKGATE,
+ REGS_DCP_BASE + HW_DCP_CTRL);
+
+ /* Initialize control registers */
+ __raw_writel(DCP_CTRL_INIT, REGS_DCP_BASE + HW_DCP_CTRL);
+ __raw_writel(DCP_CHANNELCTRL_INIT, REGS_DCP_BASE + HW_DCP_CHANNELCTRL);
+
+ /* The loader does not enable context switching. Give the context
+ * buffer pointer an illegal address so if context switching is
+ * inadvertantly enabled, the dcp will return an error instead of
+ * trashing good memory. The dcp dma cannot access rom, so any rom
+ * address will do.
+ */
+ __raw_writel(0xFFFF0000, REGS_DCP_BASE + HW_DCP_CONTEXT);
+
+ stmp3xxx_clearl(-1, REGS_DCP_BASE + HW_DCP_CHnSTAT(ROM_DCP_CHAN));
+ stmp3xxx_clearl(-1, REGS_DCP_BASE + HW_DCP_STAT);
+
+ da->hw_packet.pNext = 0;
+ da->hw_packet.pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE |
+ BM_DCP_PACKET1_ENABLE_CIPHER | BM_DCP_PACKET1_OTP_KEY |
+ BM_DCP_PACKET1_INTERRUPT |
+ (cmd == DBS_ENC ? BM_DCP_PACKET1_CIPHER_ENCRYPT : 0);
+ da->hw_packet.pkt2 = BF(0, DCP_PACKET2_CIPHER_CFG) |
+ BF(0, DCP_PACKET2_KEY_SELECT) |
+ BF(BV_DCP_PACKET2_CIPHER_MODE__ECB, DCP_PACKET2_CIPHER_MODE) |
+ BF(BV_DCP_PACKET2_CIPHER_SELECT__AES128, DCP_PACKET2_CIPHER_SELECT);
+ da->hw_packet.pSrc = dbd->dma_area_phys +
+ offsetof(struct dma_area, block);
+ da->hw_packet.pDst = da->hw_packet.pSrc; /* in-place */
+ da->hw_packet.size = 16;
+ da->hw_packet.pPayload = 0;
+ da->hw_packet.stat = 0;
+
+ /* Load the work packet pointer and bump the channel semaphore */
+ __raw_writel(dbd->dma_area_phys +
+ offsetof(struct dma_area, hw_packet),
+ REGS_DCP_BASE + HW_DCP_CHnCMDPTR(ROM_DCP_CHAN));
+ __raw_writel(BF(1, DCP_CHnSEMA_INCREMENT),
+ REGS_DCP_BASE + HW_DCP_CHnSEMA(ROM_DCP_CHAN));
+
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ while (time_before(jiffies, timeout) &&
+ (__raw_readl(REGS_DCP_BASE + HW_DCP_STAT) &
+ BF(ROM_DCP_CHAN_MASK, DCP_STAT_IRQ)) == 0)
+ cpu_relax();
+
+ if (!time_before(jiffies, timeout)) {
+ dev_err(dbd->dev, "Timeout while waiting STAT\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((__raw_readl(HW_DCP_CHnSTAT(ROM_DCP_CHAN)) & 0xff) != 0) {
+ dev_err(dbd->dev, "Channel stat error 0x%02x\n",
+ __raw_readl(REGS_DCP_BASE +
+ HW_DCP_CHnSTAT(ROM_DCP_CHAN)) & 0xff);
+ return -EFAULT;
+ }
+
+ if (copy_to_user(argp, da->block, 16))
+ return -EFAULT;
+
+ return 0;
+}
+
+static struct file_operations stmp3xxx_dcp_bootstream_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = stmp3xxx_dcp_bootstream_ioctl,
+};
+
+static struct miscdevice stmp3xxx_dcp_bootstream_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "dcpboot",
+ .fops = &stmp3xxx_dcp_bootstream_fops,
+};
+
+static int __devinit stmp3xxx_dcp_bootstream_probe(struct platform_device *pdev)
+{
+ struct stmp3xxx_dcp_bootstream_data *dbd;
+ int err;
+
+ /* we only allow a single device */
+ if (global_dbd != NULL)
+ return -ENODEV;
+
+ dbd = kzalloc(sizeof(*dbd), GFP_KERNEL);
+ if (dbd == NULL)
+ return -ENOMEM;
+ memset(dbd, 0, sizeof(*dbd));
+
+ dbd->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dbd);
+
+ err = misc_register(&stmp3xxx_dcp_bootstream_misc);
+ if (err != 0) {
+ dev_err(&pdev->dev, "Unable to register misc device\n");
+ goto err_done;
+ }
+
+ dbd->dma_area = dma_alloc_coherent(&pdev->dev, sizeof(*dbd->dma_area),
+ &dbd->dma_area_phys, GFP_KERNEL);
+ if (dbd->dma_area == NULL) {
+ dev_err(&pdev->dev, "Unable to allocate DMAable memory\n");
+ goto err_dereg;
+ }
+
+ global_dbd = dbd;
+
+ return 0;
+
+err_dereg:
+ misc_deregister(&stmp3xxx_dcp_bootstream_misc);
+err_done:
+ kfree(dbd);
+ return err;
+}
+
+static int stmp3xxx_dcp_bootstream_remove(struct platform_device *pdev)
+{
+ struct stmp3xxx_dcp_bootstream_data *dbd;
+
+ dbd = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+
+ dma_free_coherent(&pdev->dev, sizeof(*dbd->dma_area),
+ dbd->dma_area, dbd->dma_area_phys);
+ misc_deregister(&stmp3xxx_dcp_bootstream_misc);
+
+ kfree(dbd);
+
+ global_dbd = NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int stmp3xxx_dcp_bootstream_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int stmp3xxx_dcp_bootstream_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#else
+#define stmp3xxx_dcp_bootstream_suspend NULL
+#define stmp3xxx_dcp_bootstream_resume NULL
+#endif
+
+static struct platform_driver stmp3xxx_dcp_bootstream_driver = {
+ .probe = stmp3xxx_dcp_bootstream_probe,
+ .remove = stmp3xxx_dcp_bootstream_remove,
+ .suspend = stmp3xxx_dcp_bootstream_suspend,
+ .resume = stmp3xxx_dcp_bootstream_resume,
+ .driver = {
+ .name = "stmp3xxx-dcpboot",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init stmp3xxx_dcp_bootstream_init(void)
+{
+ return platform_driver_register(&stmp3xxx_dcp_bootstream_driver);
+}
+
+static void __exit stmp3xxx_dcp_bootstream_exit(void)
+{
+ platform_driver_unregister(&stmp3xxx_dcp_bootstream_driver);
+}
+
+MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>");
+MODULE_DESCRIPTION("DCP bootstream driver");
+MODULE_LICENSE("GPL");
+
+module_init(stmp3xxx_dcp_bootstream_init);
+module_exit(stmp3xxx_dcp_bootstream_exit);
diff --git a/arch/arm/plat-stmp3xxx/devices.c b/arch/arm/plat-stmp3xxx/devices.c
index 68fed4b8746a..a7b9ddb034bf 100644
--- a/arch/arm/plat-stmp3xxx/devices.c
+++ b/arch/arm/plat-stmp3xxx/devices.c
@@ -20,16 +20,26 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/list.h>
+#include <linux/delay.h>
#include <mach/dma.h>
#include <mach/platform.h>
#include <mach/stmp3xxx.h>
+#include <mach/lcdif.h>
#include <mach/regs-lcdif.h>
#include <mach/regs-uartapp.h>
#include <mach/regs-gpmi.h>
#include <mach/regs-usbctrl.h>
+#include <mach/regs-usbphy.h>
#include <mach/regs-ssp.h>
#include <mach/regs-rtc.h>
+#include <mach/regs-digctl.h>
+#include <mach/regs-ocotp.h>
+#include <mach/lcdif.h>
+#include <mach/regs-power.h>
+#include <mach/regs-clkctrl.h>
static u64 common_dmamask = DMA_BIT_MASK(32);
@@ -63,6 +73,7 @@ static struct resource appuart_resources[] = {
},
};
+
struct platform_device stmp3xxx_appuart = {
.name = "stmp3xxx-appuart",
.id = 0,
@@ -74,6 +85,11 @@ struct platform_device stmp3xxx_appuart = {
},
};
+struct platform_device stmp3xxx_dbguart = {
+ .name = "stmp3xxx-dbguart",
+ .id = -1,
+};
+
struct platform_device stmp3xxx_watchdog = {
.name = "stmp3xxx_wdt",
.id = -1,
@@ -98,12 +114,22 @@ struct platform_device stmp3xxx_touchscreen = {
.num_resources = ARRAY_SIZE(ts_resource),
};
+static struct resource keyboard_resource[] = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_LRADC_CH0,
+ .end = IRQ_LRADC_CH0,
+ },
+};
+
/*
* Keypad device
*/
struct platform_device stmp3xxx_keyboard = {
.name = "stmp3xxx-keyboard",
.id = -1,
+ .resource = keyboard_resource,
+ .num_resources = ARRAY_SIZE(keyboard_resource),
};
static struct resource gpmi_resources[] = {
@@ -155,7 +181,7 @@ static struct resource mmc1_resource[] = {
struct platform_device stmp3xxx_mmc = {
.name = "stmp3xxx-mmc",
- .id = 1,
+ .id = -1,
.dev = {
.dma_mask = &common_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
@@ -176,23 +202,48 @@ static struct resource usb_resources[] = {
},
};
+static struct fsl_usb2_platform_data udc_platform_data = {
+ .operating_mode = FSL_USB2_DR_DEVICE,
+ .phy_mode = FSL_USB2_PHY_UTMI,
+ .port_enables = FSL_USB2_DONT_REMAP,
+ .platform_init = NULL,
+ .platform_uninit = NULL,
+};
+
struct platform_device stmp3xxx_udc = {
.name = "fsl-usb2-udc",
.id = -1,
.dev = {
.dma_mask = &common_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &udc_platform_data,
},
.resource = usb_resources,
.num_resources = ARRAY_SIZE(usb_resources),
};
+static void usb_host_phy_resume(struct fsl_usb2_platform_data *pdata)
+{
+ stmp3xxx_clearl(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ REGS_USBPHY_BASE + HW_USBPHY_CTRL);
+}
+
+static struct fsl_usb2_platform_data ehci_platform_data = {
+ .operating_mode = FSL_USB2_DR_HOST,
+ .phy_mode = FSL_USB2_PHY_UTMI,
+ .port_enables = FSL_USB2_DONT_REMAP,
+ .platform_init = NULL,
+ .platform_uninit = NULL,
+ .platform_resume = usb_host_phy_resume,
+};
+
struct platform_device stmp3xxx_ehci = {
.name = "fsl-ehci",
.id = -1,
.dev = {
.dma_mask = &common_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &ehci_platform_data,
},
.resource = usb_resources,
.num_resources = ARRAY_SIZE(usb_resources),
@@ -291,12 +342,17 @@ static struct resource fb_resource[] = {
},
};
+static struct stmp3xxx_platform_fb_data stmp3xxx_framebuffer_pdata = {
+ .list = LIST_HEAD_INIT(stmp3xxx_framebuffer_pdata.list),
+};
+
struct platform_device stmp3xxx_framebuffer = {
.name = "stmp3xxx-fb",
.id = -1,
.dev = {
.dma_mask = &common_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &stmp3xxx_framebuffer_pdata,
},
.num_resources = ARRAY_SIZE(fb_resource),
.resource = fb_resource,
@@ -337,9 +393,85 @@ struct platform_device stmp3xxx_rotdec = {
.id = -1,
};
+static const struct stmp3xxx_persistent_bit_config
+stmp3xxx_persistent_bit_tab[] = {
+ { .reg = 0, .start = 0, .width = 1,
+ .name = "CLOCKSOURCE" },
+ { .reg = 0, .start = 1, .width = 1,
+ .name = "ALARM_WAKE_EN" },
+ { .reg = 0, .start = 2, .width = 1,
+ .name = "ALARM_EN" },
+ { .reg = 0, .start = 3, .width = 1,
+ .name = "CLK_SECS" },
+ { .reg = 0, .start = 4, .width = 1,
+ .name = "XTAL24MHZ_PWRUP" },
+ { .reg = 0, .start = 5, .width = 1,
+ .name = "XTAL32MHZ_PWRUP" },
+ { .reg = 0, .start = 6, .width = 1,
+ .name = "XTAL32_FREQ" },
+ { .reg = 0, .start = 7, .width = 1,
+ .name = "ALARM_WAKE" },
+ { .reg = 0, .start = 8, .width = 5,
+ .name = "MSEC_RES" },
+ { .reg = 0, .start = 13, .width = 1,
+ .name = "DISABLE_XTALOK" },
+ { .reg = 0, .start = 14, .width = 2,
+ .name = "LOWERBIAS" },
+ { .reg = 0, .start = 16, .width = 1,
+ .name = "DISABLE_PSWITCH" },
+ { .reg = 0, .start = 17, .width = 1,
+ .name = "AUTO_RESTART" },
+ { .reg = 0, .start = 18, .width = 14,
+ .name = "SPARE_ANALOG" },
+
+ { .reg = 1, .start = 0, .width = 1,
+ .name = "FORCE_RECOVERY" },
+ { .reg = 1, .start = 1, .width = 1,
+ .name = "NAND_SECONDARY_BOOT" },
+ { .reg = 1, .start = 2, .width = 1,
+ .name = "NAND_SDK_BLOCK_REWRITE" },
+ { .reg = 1, .start = 3, .width = 1,
+ .name = "SD_SPEED_ENABLE" },
+ { .reg = 1, .start = 4, .width = 1,
+ .name = "SD_INIT_SEQ_1_DISABLE" },
+ { .reg = 1, .start = 5, .width = 1,
+ .name = "SD_CMD0_DISABLE" },
+ { .reg = 1, .start = 6, .width = 1,
+ .name = "SD_INIT_SEQ_2_ENABLE" },
+ { .reg = 1, .start = 7, .width = 1,
+ .name = "OTG_ATL_ROLE_BIT" },
+ { .reg = 1, .start = 8, .width = 1,
+ .name = "OTG_HNP_BIT" },
+ { .reg = 1, .start = 9, .width = 1,
+ .name = "USB_LOW_POWER_MODE" },
+ { .reg = 1, .start = 10, .width = 1,
+ .name = "SKIP_CHECKDISK" },
+ { .reg = 1, .start = 11, .width = 1,
+ .name = "USB_BOOT_PLAYER_MODE" },
+ { .reg = 1, .start = 12, .width = 1,
+ .name = "ENUMERATE_500MA_TWICE" },
+ { .reg = 1, .start = 13, .width = 19,
+ .name = "SPARE_GENERAL" },
+
+ { .reg = 2, .start = 0, .width = 32,
+ .name = "SPARE_2" },
+ { .reg = 3, .start = 0, .width = 32,
+ .name = "SPARE_3" },
+ { .reg = 4, .start = 0, .width = 32,
+ .name = "SPARE_4" },
+ { .reg = 5, .start = 0, .width = 32,
+ .name = "SPARE_5" },
+};
+
+static struct stmp3xxx_platform_persistent_data stmp3xxx_persistent_data = {
+ .bit_config_tab = stmp3xxx_persistent_bit_tab,
+ .bit_config_cnt = ARRAY_SIZE(stmp3xxx_persistent_bit_tab),
+};
+
struct platform_device stmp3xxx_persistent = {
.name = "stmp3xxx-persistent",
.id = -1,
+ .dev.platform_data = &stmp3xxx_persistent_data,
};
struct platform_device stmp3xxx_dcp_bootstream = {
@@ -387,3 +519,28 @@ struct platform_device stmp3xxx_battery = {
.resource = battery_resource,
.num_resources = ARRAY_SIZE(battery_resource),
};
+
+struct resource viim_resources[] = {
+ [0] = {
+ .start = REGS_DIGCTL_PHYS,
+ .end = REGS_DIGCTL_PHYS + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = REGS_OCOTP_PHYS,
+ .end = REGS_OCOTP_PHYS + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device stmp3xxx_viim = {
+ .name = "mxs_viim",
+ .id = 0,
+ .resource = viim_resources,
+ .num_resources = ARRAY_SIZE(viim_resources),
+};
+
+struct platform_device stmp3xxx_spdif = {
+ .name = "stmp3xxx-spdif",
+ .id = -1,
+};
diff --git a/arch/arm/plat-stmp3xxx/dma.c b/arch/arm/plat-stmp3xxx/dma.c
index d2f497764dce..72a5745c94fb 100644
--- a/arch/arm/plat-stmp3xxx/dma.c
+++ b/arch/arm/plat-stmp3xxx/dma.c
@@ -94,15 +94,15 @@ int stmp3xxx_dma_read_semaphore(int channel)
switch (STMP3XXX_DMA_BUS(channel)) {
case STMP3XXX_BUS_APBH:
- sem = __raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
- STMP3XXX_DMA_CHANNEL(channel) * 0x70);
+ sem = __raw_readl(REGS_APBH_BASE +
+ HW_APBH_CHn_SEMA(STMP3XXX_DMA_CHANNEL(channel)));
sem &= BM_APBH_CHn_SEMA_PHORE;
sem >>= BP_APBH_CHn_SEMA_PHORE;
break;
case STMP3XXX_BUS_APBX:
- sem = __raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
- STMP3XXX_DMA_CHANNEL(channel) * 0x70);
+ sem = __raw_readl(REGS_APBX_BASE +
+ HW_APBX_CHn_SEMA(STMP3XXX_DMA_CHANNEL(channel)));
sem &= BM_APBX_CHn_SEMA_PHORE;
sem >>= BP_APBX_CHn_SEMA_PHORE;
break;
@@ -187,13 +187,13 @@ void stmp3xxx_dma_go(int channel,
switch (STMP3XXX_DMA_BUS(channel)) {
case STMP3XXX_BUS_APBH:
- c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR + 0x70 * ch;
- s = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * ch;
+ c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR(ch);
+ s = REGS_APBH_BASE + HW_APBH_CHn_SEMA(ch);
break;
case STMP3XXX_BUS_APBX:
- c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR + 0x70 * ch;
- s = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * ch;
+ c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR(ch);
+ s = REGS_APBX_BASE + HW_APBX_CHn_SEMA(ch);
break;
default:
@@ -212,13 +212,13 @@ int stmp3xxx_dma_running(int channel)
{
switch (STMP3XXX_DMA_BUS(channel)) {
case STMP3XXX_BUS_APBH:
- return (__raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
- 0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
+ return (__raw_readl(REGS_APBH_BASE +
+ HW_APBH_CHn_SEMA(STMP3XXX_DMA_CHANNEL(channel)))) &
BM_APBH_CHn_SEMA_PHORE;
case STMP3XXX_BUS_APBX:
- return (__raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
- 0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
+ return (__raw_readl(REGS_APBX_BASE +
+ HW_APBX_CHn_SEMA(STMP3XXX_DMA_CHANNEL(channel)))) &
BM_APBX_CHn_SEMA_PHORE;
default:
BUG();
@@ -323,7 +323,7 @@ void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
unsigned count)
{
void __iomem *c;
- u32 mask_clr, mask;
+ u32 mask_clr, mask, reg;
BUG_ON(chain->free_count < count);
chain->free_count -= count;
@@ -333,12 +333,12 @@ void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
switch (chain->bus) {
case STMP3XXX_BUS_APBH:
- c = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * chain->channel;
+ c = REGS_APBH_BASE + HW_APBH_CHn_SEMA(chain->channel);
mask_clr = BM_APBH_CHn_SEMA_INCREMENT_SEMA;
mask = BF(count, APBH_CHn_SEMA_INCREMENT_SEMA);
break;
case STMP3XXX_BUS_APBX:
- c = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * chain->channel;
+ c = REGS_APBX_BASE + HW_APBX_CHn_SEMA(chain->channel);
mask_clr = BM_APBX_CHn_SEMA_INCREMENT_SEMA;
mask = BF(count, APBX_CHn_SEMA_INCREMENT_SEMA);
break;
@@ -349,8 +349,11 @@ void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
/* Set counting semaphore (kicks off transfer). Assumes
peripheral has been set up correctly */
- stmp3xxx_clearl(mask_clr, c);
- stmp3xxx_setl(mask, c);
+ reg = __raw_readl(c);
+ reg &= ~mask_clr;
+ __raw_writel(reg, c);
+ reg |= mask;
+ __raw_writel(reg, c);
}
EXPORT_SYMBOL(stmp37xx_circ_advance_active);
@@ -373,6 +376,7 @@ EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
void stmp3xxx_dma_set_alt_target(int channel, int function)
{
+ u32 reg;
#if defined(CONFIG_ARCH_STMP37XX)
unsigned bits = 4;
#elif defined(CONFIG_ARCH_STMP378X)
@@ -398,8 +402,11 @@ void stmp3xxx_dma_set_alt_target(int channel, int function)
default:
BUG();
}
- stmp3xxx_clearl(mask << shift, c);
- stmp3xxx_setl(mask << shift, c);
+ reg = __raw_readl(c);
+ reg &= ~(mask << shift);
+ __raw_writel(reg, c);
+ reg |= mask;
+ __raw_writel(reg, c);
}
EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
diff --git a/arch/arm/plat-stmp3xxx/gpmi.c b/arch/arm/plat-stmp3xxx/gpmi.c
new file mode 100644
index 000000000000..f62c70aa13a8
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/gpmi.c
@@ -0,0 +1,40 @@
+/*
+ * Freescale STMP37XX/STMP378X GPMI module pin multiplexing
+ *
+ * Author: dmitry pervushin <dimka@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <mach/platform.h>
+
+int gpmi_pinmux_request(char *title)
+{
+ int err = 0;
+
+ err = stmp3xxx_request_pin_group(&gpmi_pins, title);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpmi_pinmux_request);
+
+void gpmi_pinmux_free(char *title)
+{
+ stmp3xxx_release_pin_group(&gpmi_pins, title);
+}
+EXPORT_SYMBOL_GPL(gpmi_pinmux_free);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>");
diff --git a/arch/arm/plat-stmp3xxx/include/mach/arc_otg.h b/arch/arm/plat-stmp3xxx/include/mach/arc_otg.h
new file mode 100644
index 000000000000..e0213b21f4ff
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/arc_otg.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_ARCH_MXC_ARC_OTG_H__
+#define __ASM_ARCH_MXC_ARC_OTG_H__
+
+#include <mach/hardware.h>
+
+/*
+ * register bits
+ */
+
+/* x_PORTSCx */
+#define PORTSC_PTS_MASK (3 << 30)/* parallel xcvr select mask */
+#define PORTSC_PTS_UTMI (0 << 30)/* UTMI/UTMI+ */
+#define PORTSC_PTS_PHILIPS (1 << 30)/* Philips classic */
+#define PORTSC_PTS_ULPI (2 << 30)/* ULPI */
+#define PORTSC_PTS_SERIAL (3 << 30)/* serial */
+#define PORTSC_STS (1 << 29)/* serial xcvr select */
+#define PORTSC_PTW (1 << 28)/* UTMI width */
+#define PORTSC_PORT_POWER (1 << 12)/* port power */
+#define PORTSC_LS_MASK (3 << 10)/* Line State mask */
+#define PORTSC_LS_SE0 (0 << 10)/* SE0 */
+#define PORTSC_LS_K_STATE (1 << 10)/* K-state */
+#define PORTSC_LS_J_STATE (2 << 10)/* J-state */
+#define PORTSC_PORT_RESET (1 << 8)/* Port reset */
+#define PORTSC_PORT_SUSPEND (1 << 7)/* Suspend */
+#define PORTSC_PORT_FORCE_RESUME (1 << 6)/* Force port resume */
+#define PORTSC_OVER_CURRENT_CHG (1 << 5)/* over current change */
+#define PORTSC_OVER_CURRENT_ACT (1 << 4)/* over currrent active */
+#define PORTSC_PORT_EN_DIS_CHANGE (1 << 3)/* port {en,dis}able change */
+#define PORTSC_PORT_ENABLE (1 << 2)/* port enabled */
+#define PORTSC_CONNECT_STATUS_CHANGE (1 << 1)/* connect status change */
+#define PORTSC_CURRENT_CONNECT_STATUS (1 << 0)/* current connect status */
+
+#define PORTSC_W1C_BITS (PORTSC_CONNECT_STATUS_CHANGE | \
+ PORTSC_PORT_EN_DIS_CHANGE | \
+ PORTSC_OVER_CURRENT_CHG)
+
+/* UOG_OTGSC Register Bits */
+/* control bits: */
+#define OTGSC_CTRL_VBUS_DISCHARGE (1 << 0)
+#define OTGSC_CTRL_VBUS_CHARGE (1 << 1)
+#define OTGSC_CTRL_OTG_TERM (1 << 3)/* controls DM pulldown */
+#define OTGSC_CTRL_DATA_PULSING (1 << 4)
+#define OTGSC_CTRL_USB_ID_PU (1 << 5)/* enable ID pullup */
+/* current status: (R/O) */
+#define OTGSC_STS_USB_ID (1 << 8)/* 0=A-device 1=B-device */
+#define OTGSC_STS_A_VBUS_VALID (1 << 9)
+#define OTGSC_STS_A_SESSION_VALID (1 << 10)
+#define OTGSC_STS_B_SESSION_VALID (1 << 11)
+#define OTGSC_STS_B_SESSION_END (1 << 12)
+#define OTGSC_STS_1ms_TIMER (1 << 13)
+#define OTGSC_STS_DATA_PULSE (1 << 14)
+/* interrupt status: (write to clear) */
+#define OTGSC_IS_MASK (0x7f << 16)
+#define OTGSC_IS_USB_ID (1 << 16)
+#define OTGSC_IS_A_VBUS_VALID (1 << 17)
+#define OTGSC_IS_A_SESSION_VALID (1 << 18)
+#define OTGSC_IS_B_SESSION_VALID (1 << 19)
+#define OTGSC_IS_B_SESSION_END (1 << 20)
+#define OTGSC_IS_1ms_TIMER (1 << 21)
+#define OTGSC_IS_DATA_PULSE (1 << 22)
+/* interrupt enables: */
+#define OTGSC_IE_MASK (0x7f << 24)
+#define OTGSC_IE_USB_ID (1 << 24)
+#define OTGSC_IE_A_VBUS_VALID (1 << 25)
+#define OTGSC_IE_A_SESSION_VALID (1 << 26)
+#define OTGSC_IE_B_SESSION_VALID (1 << 27)
+#define OTGSC_IE_B_SESSION_END (1 << 28)
+#define OTGSC_IE_1ms_TIMER (1 << 29)
+#define OTGSC_IE_DATA_PULSE (1 << 30)
+
+/* x_USBMODE */
+#define USBMODE_SLOM (1 << 3) /* setup lockout mode */
+#define USBMODE_ES (1 << 2) /* (big) endian select */
+#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
+#define USBMODE_CM_HOST (3 << 0) /* host */
+#define USBMODE_CM_DEVICE (2 << 0) /* device */
+#define USBMODE_CM_reserved (1 << 0) /* reserved */
+
+/* USBCMD */
+#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
+#define UCMD_RESET (1 << 1) /* controller reset */
+#define UCMD_ITC_NO_THRESHOLD (~(0xff << 16))/* Interrupt Threshold Control */
+
+#define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/dcp_bootstream_ioctl.h b/arch/arm/plat-stmp3xxx/include/mach/dcp_bootstream_ioctl.h
new file mode 100644
index 000000000000..aec63a5bfef4
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/dcp_bootstream_ioctl.h
@@ -0,0 +1,32 @@
+/*
+ * Freescale STMP378X DCP driver for bootstream update. Only handles the OTP KEY
+ * case and can only encrypt/decrypt.
+ *
+ * Author: Pantelis Antoniou <pantelis@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef DCP_BOOTSTREAM_IOCTL_H
+#define DCP_BOOTSTREAM_IOCTL_H
+
+/* remember to have included the proper _IO definition
+ * file before hand.
+ * For user space it's <sys/ioctl.h>
+ */
+
+#define DBS_IOCTL_BASE 'd'
+
+#define DBS_ENC _IOW(DBS_IOCTL_BASE, 0x00, uint8_t[16])
+#define DBS_DEC _IOW(DBS_IOCTL_BASE, 0x01, uint8_t[16])
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/fsl_usb.h b/arch/arm/plat-stmp3xxx/include/mach/fsl_usb.h
new file mode 100644
index 000000000000..87cc7d8a7abf
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/fsl_usb.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * USB Host side, platform-specific functionality.
+ */
+
+#include <linux/usb/fsl_xcvr.h>
+#include <mach/arc_otg.h>
+
+/* ehci_arc_hc_driver.flags value */
+#define FSL_PLATFORM_HC_FLAGS (HCD_USB2 | HCD_MEMORY)
+
+static void fsl_setup_phy(struct ehci_hcd *ehci,
+ enum fsl_usb2_phy_modes phy_mode,
+ int port_offset);
+
+static inline void fsl_platform_usb_setup(struct ehci_hcd *ehci)
+{
+ struct fsl_usb2_platform_data *pdata;
+
+ pdata = ehci_to_hcd(ehci)->self.controller->platform_data;
+ fsl_setup_phy(ehci, pdata->phy_mode, 0);
+}
+
+static inline void fsl_platform_set_host_mode(struct usb_hcd *hcd)
+{
+ unsigned int temp;
+ struct fsl_usb2_platform_data *pdata;
+
+ pdata = hcd->self.controller->platform_data;
+
+ if (pdata->xcvr_ops && pdata->xcvr_ops->set_host)
+ pdata->xcvr_ops->set_host();
+
+ /* set host mode */
+ temp = readl(hcd->regs + 0x1a8);
+ writel(temp | USBMODE_CM_HOST, hcd->regs + 0x1a8);
+}
+
+/* Needed for i2c/serial transceivers */
+static inline void
+fsl_platform_set_vbus_power(struct fsl_usb2_platform_data *pdata, int on)
+{
+}
+
+/* Set USB AHB burst length for host */
+static inline void fsl_platform_set_ahb_burst(struct usb_hcd *hcd)
+{
+}
diff --git a/arch/arm/plat-stmp3xxx/include/mach/fsl_usb_gadget.h b/arch/arm/plat-stmp3xxx/include/mach/fsl_usb_gadget.h
new file mode 100644
index 000000000000..638bfa4be52b
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/fsl_usb_gadget.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * USB Gadget side, platform-specific functionality.
+ */
+
+#include <linux/usb/fsl_xcvr.h>
+
+/* Needed for i2c/serial transceivers */
+static inline void
+fsl_platform_set_device_mode(struct fsl_usb2_platform_data *pdata)
+{
+}
+
+static inline void
+fsl_platform_pullup_enable(struct fsl_usb2_platform_data *pdata)
+{
+}
+
+static inline void
+fsl_platform_pullup_disable(struct fsl_usb2_platform_data *pdata)
+{
+}
+
+static inline void
+fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata,
+ enum usb_test_mode mode)
+{
+}
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
index e166432910ad..b70b6e39754a 100644
--- a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
+++ b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
@@ -1,12 +1,28 @@
#ifndef __MACH_GPMI_H
+#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <mach/regs-gpmi.h>
+#define GPMI_PART_CONCAT 0x8000 /* indicates that partitions
+ should be concatenated */
+
struct gpmi_platform_data {
- void *pins;
- int nr_parts;
- struct mtd_partition *parts;
- const char *part_types[];
+
+ u_int32_t uid_offset;
+ u_int32_t uid_size;
+
+ int items;
+ int io_uA;
+ char *concat_name;
+ char **concat_parts;
+ int (*pinmux) (int req);
+
+ struct {
+ const char **part_probe_types;
+ int nr_partitions;
+ struct mtd_partition *partitions;
+ } parts[];
+
};
#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/lradc.h b/arch/arm/plat-stmp3xxx/include/mach/lradc.h
new file mode 100644
index 000000000000..56b686896f29
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/lradc.h
@@ -0,0 +1,60 @@
+/*
+ * Freescale STMP37XX/STMP378X LRADC helper interface
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_LRADC_H
+#define __ASM_PLAT_LRADC_H
+
+int hw_lradc_use_channel(int);
+int hw_lradc_unuse_channel(int);
+extern u32 hw_lradc_vddio(void);
+void hw_lradc_set_delay_trigger_kick(int trigger, int value);
+void hw_lradc_configure_channel(int channel, int enable_div2,
+ int enable_acc, int samples);
+int hw_lradc_present(int channel);
+int hw_lradc_init_ladder(int channel, int trigger, unsigned sampling);
+int hw_lradc_stop_ladder(int channel, int trigger);
+void hw_lradc_set_delay_trigger(int trigger, u32 trigger_lradc,
+ u32 delay_triggers, u32 loops, u32 delays);
+void hw_lradc_clear_delay_trigger(int trigger, u32 trigger_lradc,
+ u32 delay_triggers);
+
+
+#define LRADC_CH0 0
+#define LRADC_CH1 1
+#define LRADC_CH2 2
+#define LRADC_CH3 3
+#define LRADC_CH4 4
+#define LRADC_CH5 5
+#define LRADC_CH6 6
+#define LRADC_CH7 7
+#define LRADC_TOUCH_X_PLUS LRADC_CH2
+#define LRADC_TOUCH_Y_PLUS LRADC_CH3
+#define LRADC_TOUCH_X_MINUS LRADC_CH4
+#define LRADC_TOUCH_Y_MINUS LRADC_CH5
+#define VDDIO_VOLTAGE_CH LRADC_CH6
+#define BATTERY_VOLTAGE_CH LRADC_CH7
+
+#define LRADC_CLOCK_6MHZ 0
+#define LRADC_CLOCK_4MHZ 1
+#define LRADC_CLOCK_3MHZ 2
+#define LRADC_CLOCK_2MHZ 3
+
+#define LRADC_DELAY_TRIGGER_BUTTON 0
+#define LRADC_DELAY_TRIGGER_BATTERY 1
+#define LRADC_DELAY_TRIGGER_TOUCHSCREEN 2
+
+#endif /* __ASM_PLAT_LRADC_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/memory.h b/arch/arm/plat-stmp3xxx/include/mach/memory.h
index 7b875a07a1a7..b152f0ef30c0 100644
--- a/arch/arm/plat-stmp3xxx/include/mach/memory.h
+++ b/arch/arm/plat-stmp3xxx/include/mach/memory.h
@@ -14,9 +14,50 @@
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
+#include <asm/page.h>
+#include <asm/sizes.h>
+
/*
* Physical DRAM offset.
*/
#define PHYS_OFFSET UL(0x40000000)
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_DMA_ZONE_SIZE
+#define MXC_DMA_ZONE_SIZE ((CONFIG_DMA_ZONE_SIZE * SZ_1M) >> PAGE_SHIFT)
+#else
+#define MXC_DMA_ZONE_SIZE ((12 * SZ_1M) >> PAGE_SHIFT)
+#endif
+
+static inline void __arch_adjust_zones(int node, unsigned long *zone_size,
+ unsigned long *zhole_size)
+{
+ if (node != 0)
+ return;
+ /* Create separate zone to reserve memory for DMA */
+ zone_size[1] = zone_size[0] - MXC_DMA_ZONE_SIZE;
+ zone_size[0] = MXC_DMA_ZONE_SIZE;
+ zhole_size[1] = zhole_size[0];
+ zhole_size[0] = 0;
+}
+
+#define arch_adjust_zones(node, size, holes) \
+ __arch_adjust_zones(node, size, holes)
+
+#endif
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ * address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ * to an address that the kernel can use.
+ */
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#define ISA_DMA_THRESHOLD (0x0003ffffULL)
+
+#define CONSISTENT_DMA_SIZE SZ_32M
+
#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/mmc.h b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
index ba81e1543761..5b68bff809ca 100644
--- a/arch/arm/plat-stmp3xxx/include/mach/mmc.h
+++ b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
@@ -4,11 +4,20 @@
#include <mach/regs-ssp.h>
struct stmp3xxxmmc_platform_data {
- int (*get_wp)(void);
- unsigned long (*setclock)(void __iomem *base, unsigned long);
- void (*cmd_pullup)(int);
- int (*hw_init)(void);
+ int (*hw_init)(void);
void (*hw_release)(void);
+ void (*cmd_pullup)(int enable);
+ int (*get_wp)(void);
+ unsigned long (*setclock)(unsigned long hz);
+ int read_uA;
+ int write_uA;
};
+
+extern unsigned long stmp3xxxmmc_setclock_ssp1(unsigned long hz);
+extern void stmp3xxxmmc_cmd_pullup_ssp1(int enable);
+extern void stmp3xxxmmc_hw_release_ssp1(void);
+extern int stmp3xxxmmc_hw_init_ssp1(void);
+extern int stmp3xxxmmc_get_wp(void);
+
#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/ocram-malloc.h b/arch/arm/plat-stmp3xxx/include/mach/ocram-malloc.h
new file mode 100644
index 000000000000..c8bee5352972
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/ocram-malloc.h
@@ -0,0 +1,26 @@
+/*
+ * Freescale STMP37XX/STMP378X OCRAM allocator interface
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_OCRAM_MALLOC_H
+#define __ASM_PLAT_OCRAM_MALLOC_H
+
+extern int ocram_malloc_init(void);
+
+extern void *ocram_malloc(size_t size, dma_addr_t *phys);
+extern void ocram_free(void *tofree);
+
+#endif /* __ASM_PLAT_OCRAM_MALLOC_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
index cc5af82279ad..763f59572977 100644
--- a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
+++ b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
@@ -24,7 +24,6 @@
#include <asm-generic/gpio.h>
/* Pin definitions */
-#include "pins.h"
#include <mach/pins.h>
/*
@@ -94,6 +93,10 @@ int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label);
/* Release pin */
void stmp3xxx_release_pin(unsigned id, const char *label);
+int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label);
+
+void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label);
+
void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun);
/*
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pins.h b/arch/arm/plat-stmp3xxx/include/mach/pins.h
deleted file mode 100644
index c573318e1caa..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/pins.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X Pin multiplexing interface definitions
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_PINS_H
-#define __ASM_PLAT_PINS_H
-
-#define STMP3XXX_PINID(bank, pin) (bank * 32 + pin)
-#define STMP3XXX_PINID_TO_BANK(pinid) (pinid / 32)
-#define STMP3XXX_PINID_TO_PINNUM(pinid) (pinid % 32)
-
-/*
- * Special invalid pin identificator to show a pin doesn't exist
- */
-#define PINID_NO_PIN STMP3XXX_PINID(0xFF, 0xFF)
-
-#endif /* __ASM_PLAT_PINS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/power.h b/arch/arm/plat-stmp3xxx/include/mach/power.h
new file mode 100644
index 000000000000..ac90f8621099
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/power.h
@@ -0,0 +1,67 @@
+/*
+ * Freescale STMP37XX/STMP378X voltage regulator structure declarations
+ *
+ * Embedded Alley Solutions, Inc <sources@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __VOLTAGE_H
+#define __VOLTAGE_H
+#include <linux/completion.h>
+//#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+
+struct stmp3xxx_regulator {
+ struct regulator_desc regulator;
+ struct stmp3xxx_regulator *parent;
+ struct stmp3xxx_platform_regulator_data *rdata;
+ struct completion done;
+
+ spinlock_t lock;
+ wait_queue_head_t wait_q;
+ struct notifier_block nb;
+
+ int mode;
+ int cur_voltage;
+ int cur_current;
+ int next_current;
+};
+
+
+struct stmp3xxx_platform_regulator_data {
+ char name[80];
+ char *parent_name;
+ int (*reg_register)(struct stmp3xxx_regulator *sreg);
+ int (*set_voltage)(struct stmp3xxx_regulator *sreg, int uv);
+ int (*get_voltage)(struct stmp3xxx_regulator *sreg);
+ int (*set_current)(struct stmp3xxx_regulator *sreg, int uA);
+ int (*get_current)(struct stmp3xxx_regulator *sreg);
+ int (*enable)(struct stmp3xxx_regulator *sreg);
+ int (*disable)(struct stmp3xxx_regulator *sreg);
+ int (*is_enabled)(struct stmp3xxx_regulator *sreg);
+ int (*set_mode)(struct stmp3xxx_regulator *sreg, int mode);
+ int (*get_mode)(struct stmp3xxx_regulator *sreg);
+ int (*get_optimum_mode)(struct stmp3xxx_regulator *sreg,
+ int input_uV, int output_uV, int load_uA);
+ u32 control_reg;
+ int min_voltage;
+ int max_voltage;
+ int max_current;
+ struct regulation_constraints *constraints;
+};
+
+int stmp3xxx_register_regulator(
+ struct stmp3xxx_regulator *reg_data, int reg,
+ struct regulator_init_data *initdata);
+
+#endif /* __VOLTAGE_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pwm-led.h b/arch/arm/plat-stmp3xxx/include/mach/pwm-led.h
new file mode 100644
index 000000000000..03e530727488
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/pwm-led.h
@@ -0,0 +1,25 @@
+/*
+ * Freescale STMP37XX/STMP378X PWM LED arch-dependent structure
+ * and functions declarations
+ *
+ * Author: Drew Benedetti <drewb@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_PWM_LED_H
+#define __ASM_PLAT_PWM_LED_H
+
+extern int pwm_led_pinmux_request(int, char *);
+extern void pwm_led_pinmux_free(int, char *);
+
+#endif /* __ASM_PLAT_PWM_LED_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/regulator.h b/arch/arm/plat-stmp3xxx/include/mach/regulator.h
new file mode 100644
index 000000000000..01880bd157a7
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/regulator.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __PLAT_REGULATOR_H_
+#define __PLAT_REGULATOR_H_
+#define STMP3XXX_REG5V_NOT_USB 0
+#define STMP3XXX_REG5V_IS_USB 1
+#define STMP3XXX_VDDD 0
+#define STMP3XXX_VDDA 1
+#define STMP3XXX_VDDIO 2
+#define STMP3XXX_VDDDBO 3
+#define STMP3XXX_OVERALL_CUR 4
+
+#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/rotdec.h b/arch/arm/plat-stmp3xxx/include/mach/rotdec.h
new file mode 100644
index 000000000000..6e81bb32d3b9
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/rotdec.h
@@ -0,0 +1,25 @@
+/*
+ * Freescale STMP37XX/STMP378X dev board rotary encoder arch-dependent
+ * structure and functions declarations
+ *
+ * Author: Drew Benedetti <drewb@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ASM_PLAT_ROTDEC_H
+#define __ASM_PLAT_ROTDEC_H
+
+extern int rotdec_pinmux_request(void);
+extern void rotdec_pinmux_free(void);
+
+#endif /* __ASM_PLAT_ROTDEC_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
index 2e300feaa4cf..a697124b5ce7 100644
--- a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
+++ b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
@@ -3,7 +3,7 @@
*
* Embedded Alley Solutions, Inc <source@embeddedalley.com>
*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
@@ -19,9 +19,43 @@
#define __ASM_PLAT_STMP3XXX_H
#include <linux/irq.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
extern struct sys_timer stmp3xxx_timer;
+struct stmpkbd_keypair {
+ int raw;
+ int kcode;
+};
+
+struct stmp37xx_spi_platform_data {
+ unsigned irq_pin;
+
+ int (*hw_init)(void *spi);
+ int (*hw_release)(void *spi);
+};
+
+struct stmp3xxx_persistent_bit_config {
+ int reg;
+ int start;
+ int width;
+ const char *name;
+};
+
+struct stmp3xxx_platform_persistent_data {
+ const struct stmp3xxx_persistent_bit_config *bit_config_tab;
+ int bit_config_cnt;
+};
+
+#define STMP3XXX_USB_DONT_REMAP 0x00000001
+struct stmp3xxx_usb_platform_data {
+ unsigned flags;
+ int (*phy_enable)(struct platform_device *);
+ void (*hw_init)(void);
+ void (*hw_release)(void);
+};
+
void stmp3xxx_init_irq(struct irq_chip *chip);
void stmp3xxx_init(void);
int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable);
@@ -32,18 +66,32 @@ extern struct platform_device stmp3xxx_dbguart,
stmp3xxx_keyboard,
stmp3xxx_gpmi,
stmp3xxx_mmc,
+ stmp3xxx_mmc2,
stmp3xxx_udc,
stmp3xxx_ehci,
+ stmp3xxx_usb,
stmp3xxx_rtc,
stmp3xxx_spi1,
stmp3xxx_spi2,
stmp3xxx_backlight,
stmp3xxx_rotdec,
+ stmp3xxx_ssp1,
+ stmp3xxx_ssp2,
stmp3xxx_dcp,
stmp3xxx_dcp_bootstream,
stmp3xxx_persistent,
stmp3xxx_framebuffer,
- stmp3xxx_battery;
+ stmp3xxx_battery,
+ stmp378x_i2c,
+ stmp378x_pxp,
+ stmp378x_audio,
+ stmp3xxx_viim,
+ stmp3xxx_spdif;
+#ifdef CONFIG_PM
+suspend_state_t stmp37xx_pm_get_target(void);
+int stmp37xx_pm_sleep_was_deep(void);
+#endif
+
int stmp3xxx_ssp1_device_register(void);
int stmp3xxx_ssp2_device_register(void);
@@ -51,4 +99,6 @@ struct pin_group;
void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label);
int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label);
+int get_evk_board_version(void);
+
#endif /* __ASM_PLAT_STMP3XXX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/unique-id.h b/arch/arm/plat-stmp3xxx/include/mach/unique-id.h
new file mode 100644
index 000000000000..ee22ec2502c5
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/unique-id.h
@@ -0,0 +1,30 @@
+/*
+ * Unique ID interface for ID storage providers
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __UNIQUE_ID_H
+#define __UNIQUE_ID_H
+
+struct uid_ops {
+ ssize_t (*id_show)(void *context, char *page, int ascii);
+ ssize_t (*id_store)(void *context, const char *page,
+ size_t count, int ascii);
+};
+
+struct kobject *uid_provider_init(const char *name,
+ struct uid_ops *ops, void *context);
+void uid_provider_remove(const char *name);
+#endif
diff --git a/arch/arm/plat-stmp3xxx/lradc.c b/arch/arm/plat-stmp3xxx/lradc.c
new file mode 100644
index 000000000000..ed0b89323add
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/lradc.c
@@ -0,0 +1,332 @@
+/*
+ * Freescale STMP37XX/STMP378X LRADC helper routines
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <mach/hardware.h>
+#include <linux/delay.h>
+#include <mach/platform.h>
+#include <mach/stmp3xxx.h>
+#include <mach/regs-lradc.h>
+#include <mach/lradc.h>
+
+static int channels[8];
+
+int hw_lradc_use_channel(int channel)
+{
+ if (channel < 0 || channel > 7)
+ return -EINVAL;
+ channels[channel]++;
+ return 0;
+}
+EXPORT_SYMBOL(hw_lradc_use_channel);
+
+int hw_lradc_unuse_channel(int channel)
+{
+ if (channel < 0 || channel > 7)
+ return -EINVAL;
+ channels[channel]--;
+ return 0;
+}
+EXPORT_SYMBOL(hw_lradc_unuse_channel);
+
+void hw_lradc_reinit(int enable_ground_ref, unsigned freq)
+{
+ stmp3xxx_setl(BM_LRADC_CTRL0_SFTRST, REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ udelay(1);
+ stmp3xxx_clearl(BM_LRADC_CTRL0_SFTRST,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+
+ /* Clear the Clock Gate for normal operation */
+ stmp3xxx_clearl(BM_LRADC_CTRL0_CLKGATE,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+
+ if (enable_ground_ref)
+ stmp3xxx_setl(BM_LRADC_CTRL0_ONCHIP_GROUNDREF,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ else
+ stmp3xxx_clearl(BM_LRADC_CTRL0_ONCHIP_GROUNDREF,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+
+ stmp3xxx_clearl(BM_LRADC_CTRL3_CYCLE_TIME,
+ REGS_LRADC_BASE + HW_LRADC_CTRL3);
+ stmp3xxx_setl(BF(freq, LRADC_CTRL3_CYCLE_TIME),
+ REGS_LRADC_BASE + HW_LRADC_CTRL3);
+
+ stmp3xxx_clearl(BM_LRADC_CTRL4_LRADC6SELECT |
+ BM_LRADC_CTRL4_LRADC7SELECT,
+ REGS_LRADC_BASE + HW_LRADC_CTRL4);
+ stmp3xxx_setl(BF(VDDIO_VOLTAGE_CH, LRADC_CTRL4_LRADC6SELECT),
+ REGS_LRADC_BASE + HW_LRADC_CTRL4);
+ stmp3xxx_setl(BF(BATTERY_VOLTAGE_CH, LRADC_CTRL4_LRADC7SELECT),
+ REGS_LRADC_BASE + HW_LRADC_CTRL4);
+}
+
+int hw_lradc_init_ladder(int channel, int trigger, unsigned sampling)
+{
+ /*
+ * check if the lradc channel is present in this product
+ */
+ if (!hw_lradc_present(channel))
+ return -ENODEV;
+
+ hw_lradc_configure_channel(channel, !0 /* div2 */ ,
+ 0 /* acc */ ,
+ 0 /* num_samples */ );
+
+ /* Setup the trigger loop forever */
+ hw_lradc_set_delay_trigger(trigger, 1 << channel,
+ 1 << trigger, 0, sampling);
+
+ /* Clear the accumulator & NUM_SAMPLES */
+ stmp3xxx_clearl(0xFFFFFFFF, REGS_LRADC_BASE + HW_LRADC_CHn(channel));
+ return 0;
+}
+
+EXPORT_SYMBOL(hw_lradc_init_ladder);
+
+int hw_lradc_stop_ladder(int channel, int trigger)
+{
+ /*
+ * check if the lradc channel is present in this product
+ */
+ if (!hw_lradc_present(channel))
+ return -ENODEV;
+ hw_lradc_clear_delay_trigger(trigger, 1 << channel, 1 << trigger);
+ return 0;
+}
+
+EXPORT_SYMBOL(hw_lradc_stop_ladder);
+
+int hw_lradc_present(int channel)
+{
+ if (channel < 0 || channel > 7)
+ return 0;
+ return __raw_readl(REGS_LRADC_BASE + HW_LRADC_STATUS)
+ & (1 << (16 + channel));
+}
+
+EXPORT_SYMBOL(hw_lradc_present);
+
+void hw_lradc_configure_channel(int channel, int enable_div2,
+ int enable_acc, int samples)
+{
+ if (enable_div2)
+ stmp3xxx_setl(BF(1 << channel, LRADC_CTRL2_DIVIDE_BY_TWO),
+ REGS_LRADC_BASE + HW_LRADC_CTRL2);
+ else
+ stmp3xxx_clearl(BF(1 << channel, LRADC_CTRL2_DIVIDE_BY_TWO),
+ REGS_LRADC_BASE + HW_LRADC_CTRL2);
+
+ /* Clear the accumulator & NUM_SAMPLES */
+ stmp3xxx_clearl(0xFFFFFFFF, REGS_LRADC_BASE + HW_LRADC_CHn(channel));
+
+ /* Sets NUM_SAMPLES bitfield of HW_LRADC_CHn register. */
+ stmp3xxx_clearl(BM_LRADC_CHn_NUM_SAMPLES,
+ REGS_LRADC_BASE + HW_LRADC_CHn(channel));
+ stmp3xxx_setl(BF(samples, LRADC_CHn_NUM_SAMPLES),
+ REGS_LRADC_BASE + HW_LRADC_CHn(channel));
+
+ if (enable_acc)
+ stmp3xxx_setl(BM_LRADC_CHn_ACCUMULATE,
+ REGS_LRADC_BASE + HW_LRADC_CHn(channel));
+ else
+ stmp3xxx_clearl(BM_LRADC_CHn_ACCUMULATE,
+ REGS_LRADC_BASE + HW_LRADC_CHn(channel));
+}
+
+EXPORT_SYMBOL(hw_lradc_configure_channel);
+
+void hw_lradc_set_delay_trigger(int trigger, u32 trigger_lradc,
+ u32 delay_triggers, u32 loops, u32 delays)
+{
+ /* set TRIGGER_LRADCS in HW_LRADC_DELAYn */
+ stmp3xxx_setl(BF(trigger_lradc, LRADC_DELAYn_TRIGGER_LRADCS),
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+ stmp3xxx_setl(BF(delay_triggers, LRADC_DELAYn_TRIGGER_DELAYS),
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+
+ stmp3xxx_clearl(BM_LRADC_DELAYn_LOOP_COUNT | BM_LRADC_DELAYn_DELAY,
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+ stmp3xxx_setl(BF(loops, LRADC_DELAYn_LOOP_COUNT),
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+ stmp3xxx_setl(BF(delays, LRADC_DELAYn_DELAY),
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+}
+
+EXPORT_SYMBOL(hw_lradc_set_delay_trigger);
+
+void hw_lradc_clear_delay_trigger(int trigger, u32 trigger_lradc,
+ u32 delay_triggers)
+{
+ stmp3xxx_clearl(BF(trigger_lradc, LRADC_DELAYn_TRIGGER_LRADCS),
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+ stmp3xxx_clearl(BF(delay_triggers, LRADC_DELAYn_TRIGGER_DELAYS),
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+}
+
+EXPORT_SYMBOL(hw_lradc_clear_delay_trigger);
+
+void hw_lradc_set_delay_trigger_kick(int trigger, int value)
+{
+ if (value)
+ stmp3xxx_setl(BM_LRADC_DELAYn_KICK,
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+ else
+ stmp3xxx_clearl(BM_LRADC_DELAYn_KICK,
+ REGS_LRADC_BASE + HW_LRADC_DELAYn(trigger));
+}
+
+EXPORT_SYMBOL(hw_lradc_set_delay_trigger_kick);
+
+u32 hw_lradc_vddio(void)
+{
+ /* Clear the Soft Reset and Clock Gate for normal operation */
+ stmp3xxx_clearl(BM_LRADC_CTRL0_SFTRST | BM_LRADC_CTRL0_CLKGATE,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+
+ /*
+ * Clear the divide by two for channel 6 since
+ * it has a HW divide-by-two built in.
+ */
+ stmp3xxx_clearl(BF(1 << VDDIO_VOLTAGE_CH, LRADC_CTRL2_DIVIDE_BY_TWO),
+ REGS_LRADC_BASE + HW_LRADC_CTRL2);
+
+ /* Clear the accumulator & NUM_SAMPLES */
+ stmp3xxx_clearl(0xFFFFFFFF,
+ REGS_LRADC_BASE + HW_LRADC_CHn(VDDIO_VOLTAGE_CH));
+
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC6_IRQ,
+ REGS_LRADC_BASE + HW_LRADC_CTRL1);
+
+ /*
+ * Get VddIO; this is the max scale value for the button resistor
+ * ladder.
+ * schedule ch 6:
+ */
+ stmp3xxx_setl(BF(1 << VDDIO_VOLTAGE_CH, LRADC_CTRL0_SCHEDULE),
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+
+ /* wait for completion */
+ while ((__raw_readl(REGS_LRADC_BASE + HW_LRADC_CTRL1)
+ & BM_LRADC_CTRL1_LRADC6_IRQ) != BM_LRADC_CTRL1_LRADC6_IRQ)
+ cpu_relax();
+
+ /* Clear the interrupt flag */
+ stmp3xxx_clearl(BM_LRADC_CTRL1_LRADC6_IRQ,
+ REGS_LRADC_BASE + HW_LRADC_CTRL1);
+
+ /* read ch 6 value. */
+ return __raw_readl(REGS_LRADC_BASE + HW_LRADC_CHn(6))
+ & BM_LRADC_CHn_VALUE;
+}
+
+EXPORT_SYMBOL(hw_lradc_vddio);
+
+static u32 lradc_registers[0x16];
+static int do_gate;
+
+static int hw_lradc_suspend(struct sys_device *dev, pm_message_t state)
+{
+ int i;
+
+ do_gate = 1;
+ for (i = 0; i < ARRAY_SIZE(channels); i++)
+ if (channels[i] > 0) {
+ do_gate = 0;
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(lradc_registers); i++)
+ lradc_registers[i] = __raw_readl(REGS_LRADC_BASE + (i << 4));
+
+ if (do_gate)
+ stmp3xxx_setl(BM_LRADC_CTRL0_CLKGATE,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ return 0;
+}
+
+static int hw_lradc_resume(struct sys_device *dev)
+{
+ int i;
+
+ if (do_gate) {
+ stmp3xxx_setl(BM_LRADC_CTRL0_SFTRST,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ udelay(10);
+ stmp3xxx_clearl(BM_LRADC_CTRL0_SFTRST |
+ BM_LRADC_CTRL0_CLKGATE,
+ REGS_LRADC_BASE + HW_LRADC_CTRL0);
+ }
+ for (i = 0; i < ARRAY_SIZE(lradc_registers); i++)
+ __raw_writel(lradc_registers[i], REGS_LRADC_BASE + (i << 4));
+ return 0;
+}
+
+static struct sysdev_class stmp3xxx_lradc_sysclass = {
+ .name = "stmp3xxx-lradc",
+#ifdef CONFIG_PM
+ .suspend = hw_lradc_suspend,
+ .resume = hw_lradc_resume,
+#endif
+};
+
+static struct sys_device stmp3xxx_lradc_device = {
+ .id = -1,
+ .cls = &stmp3xxx_lradc_sysclass,
+};
+
+static int __initdata lradc_freq = LRADC_CLOCK_6MHZ;
+
+static int __init lradc_freq_setup(char *str)
+{
+ long freq;
+
+ if (strict_strtol(str, 0, &freq) < 0)
+ return 0;
+
+ if (freq < 0)
+ return 0;
+ if (freq >= 6)
+ lradc_freq = LRADC_CLOCK_6MHZ;
+ else if (freq >= 4)
+ lradc_freq = LRADC_CLOCK_4MHZ;
+ else if (freq >= 3)
+ lradc_freq = LRADC_CLOCK_3MHZ;
+ else if (freq >= 2)
+ lradc_freq = LRADC_CLOCK_2MHZ;
+ else
+ return 0;
+ return 1;
+}
+
+__setup("lradc_freq=", lradc_freq_setup);
+
+static int __init hw_lradc_init(void)
+{
+ hw_lradc_reinit(0, lradc_freq);
+ sysdev_class_register(&stmp3xxx_lradc_sysclass);
+ sysdev_register(&stmp3xxx_lradc_device);
+ return 0;
+}
+
+subsys_initcall(hw_lradc_init);
diff --git a/arch/arm/plat-stmp3xxx/mmc.c b/arch/arm/plat-stmp3xxx/mmc.c
new file mode 100644
index 000000000000..75dc3a9f282a
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/mmc.c
@@ -0,0 +1,148 @@
+/*
+ * Freescale STMP37XX/STMP378X MMC pin multiplexing
+ *
+ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <mach/pinmux.h>
+#include <mach/stmp3xxx.h>
+#include <mach/platform.h>
+#include <mach/mmc.h>
+#include <mach/regs-ssp.h>
+
+#if defined(CONFIG_MACH_STMP378X)
+#define MMC_POWER PINID_PWM3
+#define MMC_WP PINID_PWM4
+#elif defined(CONFIG_MACH_STMP37XX)
+#define MMC_POWER PINID_PWM3
+#define MMC_WP PINID_PWM4
+#else
+#define MMC_POWER PINID_NO_PIN
+#define MMC_WP PINID_NO_PIN
+#endif
+
+static int mmc_drive_power;
+static int mmc_wp_supported;
+
+static struct pin_desc mmc_pins_desc[] = {
+ { PINID_SSP1_DATA0, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_DATA1, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_DATA2, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_DATA3, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_CMD, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
+ { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+ { PINID_SSP1_DETECT, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
+};
+
+static struct pin_group mmc_pins = {
+ .pins = mmc_pins_desc,
+ .nr_pins = ARRAY_SIZE(mmc_pins_desc),
+};
+
+int stmp3xxxmmc_get_wp(void)
+{
+ if (mmc_wp_supported)
+ return gpio_get_value(MMC_WP);
+
+ return 0;
+}
+
+int stmp3xxxmmc_hw_init_ssp1(void)
+{
+ int ret;
+
+ mmc_drive_power = stmp3xxx_valid_pin(MMC_POWER);
+ mmc_wp_supported = stmp3xxx_valid_pin(MMC_WP);
+
+ ret = stmp3xxx_request_pin_group(&mmc_pins, "mmc");
+ if (ret)
+ goto out;
+
+ if (mmc_wp_supported) {
+ /* Configure write protect GPIO pin */
+ ret = gpio_request(MMC_WP, "mmc wp");
+ if (ret)
+ goto out_wp;
+
+ gpio_set_value(MMC_WP, 0);
+ gpio_direction_input(MMC_WP);
+ }
+
+ if (mmc_drive_power) {
+ /* Configure POWER pin as gpio to drive power to MMC slot */
+ ret = gpio_request(MMC_POWER, "mmc power");
+ if (ret)
+ goto out_power;
+
+ gpio_direction_output(MMC_POWER, 0);
+ mdelay(100);
+ }
+
+ return 0;
+
+out_power:
+ if (mmc_wp_supported)
+ gpio_free(MMC_WP);
+out_wp:
+ stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+out:
+ return ret;
+}
+
+void stmp3xxxmmc_hw_release_ssp1(void)
+{
+ if (mmc_drive_power)
+ gpio_free(MMC_POWER);
+
+ if (mmc_wp_supported)
+ gpio_free(MMC_WP);
+
+ stmp3xxx_release_pin_group(&mmc_pins, "mmc");
+}
+
+void stmp3xxxmmc_cmd_pullup_ssp1(int enable)
+{
+ stmp3xxx_pin_pullup(PINID_SSP1_CMD, enable, "mmc");
+}
+
+unsigned long stmp3xxxmmc_setclock_ssp1(unsigned long hz)
+{
+ struct clk *ssp = clk_get(NULL, "ssp"), *parent;
+ char *p;
+ long r;
+
+ /* using SSP1, no timeout, clock rate 1 */
+ __raw_writel(BF(2, SSP_TIMING_CLOCK_DIVIDE) |
+ BF(0xFFFF, SSP_TIMING_TIMEOUT),
+ REGS_SSP1_BASE + HW_SSP_TIMING);
+
+ if (hz > 1000000)
+ p = "io";
+ else
+ p = "osc_24M";
+
+ parent = clk_get(NULL, p);
+ clk_set_parent(ssp, parent);
+ r = clk_set_rate(ssp, 2 * hz / 1000);
+ clk_put(parent);
+ clk_put(ssp);
+
+ return hz;
+}
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
index 6d6b1a468eda..375578d58c27 100644
--- a/arch/arm/plat-stmp3xxx/pinmux.c
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -15,7 +15,7 @@
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
-#define DEBUG
+//#define DEBUG
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/arch/arm/plat-stmp3xxx/power-test.c b/arch/arm/plat-stmp3xxx/power-test.c
new file mode 100644
index 000000000000..66f15f562798
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/power-test.c
@@ -0,0 +1,213 @@
+/*
+ * Power consumption test module
+ *
+ * Author: Dmitrij Frasenyak <sed@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+static struct regulator *reg;
+static struct regulator *freg;
+
+static struct timer_list pt_timer;
+static int timer_delay = 5*60*1000; /* 5min */
+static DEFINE_MUTEX(run_mutex);
+
+
+#define REG_GET() do {\
+ if (!reg) {\
+ reg = regulator_get(NULL, "power-test-1");\
+ if (!reg || IS_ERR(reg)) {\
+ reg = NULL ; return -ENODEV;\
+ } \
+ } \
+} while (0);
+
+static void timer_func(unsigned long data)
+{
+ regulator_set_current_limit(reg, 0, 0);
+ mutex_unlock(&run_mutex);
+}
+
+static ssize_t pt_mode_set(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ REG_GET();
+ if (buf[0] == 'f')
+ regulator_set_mode(reg, REGULATOR_MODE_FAST);
+ else
+ regulator_set_mode(reg, REGULATOR_MODE_NORMAL);
+ return size;
+}
+
+static ssize_t pt_mode_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ REG_GET();
+ if (regulator_get_mode(reg) == REGULATOR_MODE_FAST)
+ return snprintf(buf, 5, "fast\n");
+ else
+ return snprintf(buf, 7, "normal\n");
+}
+
+static ssize_t pt_val_fset(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, ret;
+ ret = sscanf(buf, "%u", &i);
+ if (ret != 1)
+ return -EINVAL;
+
+ if (!freg) {
+ freg = regulator_get(NULL, "stmp3xxx-bl-1");
+ if (!freg || IS_ERR(freg)) {
+ freg = NULL ; return -ENODEV;
+ }
+ }
+ regulator_set_mode(freg, REGULATOR_MODE_NORMAL);
+
+ if (!regulator_set_current_limit(freg, i, i))
+ printk(KERN_ERR "got backlight reg\n");
+ else
+ printk(KERN_ERR "failed to get backlight reg");
+
+ return size;
+}
+
+
+static ssize_t pt_val_set(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, ret;
+ REG_GET();
+
+ ret = sscanf(buf, "%u", &i);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&run_mutex);
+ if (!regulator_set_current_limit(reg, i, i)) {
+ mod_timer(&pt_timer,
+ jiffies + msecs_to_jiffies(timer_delay));
+ return size;
+ } else {
+ mutex_unlock(&run_mutex);
+ return -EPERM;
+ }
+
+}
+
+static ssize_t pt_val_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ REG_GET();
+ return sprintf(buf, "%d\n", regulator_get_current_limit(reg));
+}
+
+static ssize_t pt_timeout_set(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i, ret;
+ REG_GET();
+
+ ret = sscanf(buf, "%u", &i);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&run_mutex);
+ timer_delay = 1000*i ;
+ mutex_unlock(&run_mutex);
+
+ return size;
+}
+
+static ssize_t pt_timeout_show(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ REG_GET();
+ return sprintf(buf, "%d\n", timer_delay);
+}
+
+static DEVICE_ATTR(mode, 0644, pt_mode_show, pt_mode_set);
+static DEVICE_ATTR(val, 0644, pt_val_show, pt_val_set);
+static DEVICE_ATTR(fval, 0644, pt_val_show, pt_val_fset);
+static DEVICE_ATTR(timeout, 0644, pt_timeout_show, pt_timeout_set);
+
+static int stmp3xxx_power_test_remove(struct platform_device *pdev)
+{
+ if (reg)
+ regulator_put(reg);
+
+ device_remove_file(&pdev->dev, &dev_attr_mode);
+ device_remove_file(&pdev->dev, &dev_attr_val);
+ device_remove_file(&pdev->dev, &dev_attr_timeout);
+ device_remove_file(&pdev->dev, &dev_attr_fval);
+ return 0;
+}
+
+static int stmp3xxx_power_test_probe(struct platform_device *pdev)
+{
+ int ret;
+ init_timer(&pt_timer);
+ pt_timer.data = 0;
+ pt_timer.function = timer_func;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_mode);
+ ret |= device_create_file(&pdev->dev, &dev_attr_val);
+ ret |= device_create_file(&pdev->dev, &dev_attr_fval);
+ ret |= device_create_file(&pdev->dev, &dev_attr_timeout);
+ return ret;
+}
+
+static struct platform_driver stmp3xxx_power_test_driver = {
+ .probe = stmp3xxx_power_test_probe,
+ .remove = stmp3xxx_power_test_remove,
+ .driver = {
+ .name = "stmp3xxx-power-test",
+ .owner = THIS_MODULE,
+ },
+};
+
+struct platform_device stmp3xxx_pt = {
+ .name = "stmp3xxx-power-test",
+ .id = -1,
+};
+
+static int __init stmp3xxx_power_test_init(void)
+{
+
+ platform_device_register(&stmp3xxx_pt);
+ return platform_driver_register(&stmp3xxx_power_test_driver);
+}
+
+static void __exit stmp3xxx_power_test_exit(void)
+{
+ platform_driver_unregister(&stmp3xxx_power_test_driver);
+ platform_device_unregister(&stmp3xxx_pt);
+}
+
+MODULE_AUTHOR("<sed@embeddedalley.com>");
+MODULE_DESCRIPTION("Power test driver");
+MODULE_LICENSE("GPL");
+
+module_init(stmp3xxx_power_test_init);
+module_exit(stmp3xxx_power_test_exit);
diff --git a/arch/arm/plat-stmp3xxx/rotdec.c b/arch/arm/plat-stmp3xxx/rotdec.c
new file mode 100644
index 000000000000..d390102c1559
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/rotdec.c
@@ -0,0 +1,39 @@
+/*
+ * Freescale STMP378X Rotary Encoder module pin multiplexing
+ *
+ * Author: Drew Benedetti <drewb@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <mach/pins.h>
+#include "pinmux.h"
+
+#define TITLE "stmp3xxx-rotdec"
+
+int rotdec_pinmux_request(void)
+{
+ return stmp3xxx_request_pin_group(&rotdec_pins, TITLE);
+}
+EXPORT_SYMBOL_GPL(rotdec_pinmux_request);
+
+void rotdec_pinmux_free(void)
+{
+ stmp3xxx_release_pin_group(&spdif_pins, TITLE);
+}
+EXPORT_SYMBOL_GPL(rotdec_pinmux_free);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>");
diff --git a/arch/arm/plat-stmp3xxx/spi.c b/arch/arm/plat-stmp3xxx/spi.c
new file mode 100644
index 000000000000..21242dfd5c9a
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/spi.c
@@ -0,0 +1,106 @@
+/*
+ * Freescale STMP37XX/STMP378X SPI module pin multiplexing
+ *
+ * Author: dmitry pervushin <dimka@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <mach/stmp3xxx.h>
+#include <mach/pinmux.h>
+
+/*
+ These pins are:
+ SCK (SSPx_SCK)
+ MOSI (SSPx_CMD)
+ MISO (SSPx_DATA0)
+ SSn (SSPx_DATA3)
+ Please add new pins in the same order, thanks :)
+*/
+static struct pin_desc ssp_pins_desc[2][4] = {
+ [0] = {
+ { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0, },
+ { PINID_SSP1_CMD, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+ { PINID_SSP1_DATA0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+ { PINID_SSP1_DATA3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
+ },
+ [1] = {
+#if defined(CONFIG_ARCH_STMP37XX)
+ { PINID_GPMI_IRQ, PIN_FUN3, PIN_8MA, PIN_3_3V, 0, },
+ { PINID_GPMI_RDY2, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+ { PINID_EMI_CE2N, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+ { PINID_GPMI_D03, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+#elif defined(CONFIG_ARCH_STMP378X)
+ { PINID_GPMI_WRN, PIN_FUN3, PIN_8MA, PIN_3_3V, 0, },
+ { PINID_GPMI_RDY1, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+ { PINID_GPMI_D00, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+ { PINID_GPMI_D03, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
+#endif
+ },
+};
+
+static struct pin_group ssp_pins[2] = {
+ [0] = {
+ .pins = ssp_pins_desc[0],
+ .nr_pins = ARRAY_SIZE(ssp_pins_desc[0]),
+ },
+ [1] = {
+ .pins = ssp_pins_desc[1],
+ .nr_pins = ARRAY_SIZE(ssp_pins_desc[1]),
+ },
+};
+
+int stmp37xx_spi_pins_request(char *id, int ssp)
+{
+ return stmp3xxx_request_pin_group(&ssp_pins[ssp-1], id);
+}
+EXPORT_SYMBOL_GPL(stmp37xx_spi_pins_request);
+
+void stmp37xx_spi_pins_release(char *id, int ssp)
+{
+ stmp3xxx_release_pin_group(&ssp_pins[ssp-1], id);
+}
+EXPORT_SYMBOL_GPL(stmp37xx_spi_pins_release);
+
+int stmp37xx_spi_enc_init(void *spi_dev)
+{
+ struct spi_device *spi = spi_dev;
+ struct stmp37xx_spi_platform_data *data = spi->dev.platform_data;
+
+ gpio_request(data->irq_pin, dev_name(&spi->dev));
+ gpio_direction_input(data->irq_pin);
+ set_irq_type(gpio_to_irq(data->irq_pin), IRQ_TYPE_EDGE_FALLING);
+ spi->irq = gpio_to_irq(data->irq_pin);
+ dev_dbg(&spi->dev, "Assigned IRQ %d(%s)\n", spi->irq, __func__);
+ return 0;
+}
+
+int stmp37xx_spi_enc_release(void *spi_dev)
+{
+ struct spi_device *spi = spi_dev;
+ struct stmp37xx_spi_platform_data *data = spi->dev.platform_data;
+
+ set_irq_type(data->irq_pin, IRQ_TYPE_NONE);
+ gpio_free(data->irq_pin);
+ return 0;
+}
+
+MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-stmp3xxx/unique-id.c b/arch/arm/plat-stmp3xxx/unique-id.c
new file mode 100644
index 000000000000..b25cab17555a
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/unique-id.c
@@ -0,0 +1,198 @@
+/*
+ * Unique ID manipulation sysfs access generic functions
+ *
+ * Author: dmitry pervushin <dimka@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+
+#include <mach/unique-id.h>
+
+static int unlock;
+static spinlock_t u_lock;
+static const unsigned long UID_AUTOLOCK_TIMEOUT = HZ * 60 * 3;
+static struct timer_list u_timer;
+
+static void uid_timer_autolock(unsigned long param)
+{
+ struct timer_list *tmr = (struct timer_list *)param;
+
+ if (spin_trylock(&u_lock)) {
+ if (unlock)
+ pr_debug("%s: locked down.\n", __func__);
+ unlock = 0;
+ spin_unlock(&u_lock);
+ }
+ mod_timer(tmr, jiffies + UID_AUTOLOCK_TIMEOUT);
+}
+
+static LIST_HEAD(uid_provider_list);
+
+struct uid_provider {
+ struct kobject *kobj;
+ struct list_head list;
+ struct uid_ops *ops;
+ void *context;
+};
+
+static struct uid_provider *uid_provider_find(const char *name);
+
+#define UID_FWD_SYSFS_FILE(var, file, param) \
+ static ssize_t var##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+ { \
+ struct uid_provider *p = \
+ uid_provider_find(kobject_name(kobj)); \
+ ssize_t r; \
+ BUG_ON(p == NULL); \
+ r = (p->ops && p->ops->file##_show) ? \
+ p->ops->file##_show(p->context, buf, param) : 0;\
+ return r; \
+ } \
+ \
+ static ssize_t var##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buf, \
+ size_t count) \
+ { \
+ struct uid_provider *p = \
+ uid_provider_find(kobject_name(kobj)); \
+ ssize_t r; \
+ int ul; \
+ BUG_ON(p == NULL); \
+ spin_lock(&u_lock); \
+ ul = unlock; \
+ spin_unlock(&u_lock); \
+ if (ul) \
+ r = (p->ops && p->ops->file##_store) ? \
+ p->ops->file##_store(p->context, buf, count, param) \
+ : count; \
+ else \
+ r = -EACCES; \
+ return r; \
+ }
+
+struct kobject *uid_kobj;
+
+#define UID_ATTR(_name, _varname) \
+ static struct kobj_attribute _varname##_attr = \
+ __ATTR(_name, 0644, _varname##_show, _varname##_store)
+
+UID_FWD_SYSFS_FILE(id, id, 1);
+UID_FWD_SYSFS_FILE(id_bin, id, 0);
+UID_ATTR(id, id);
+UID_ATTR(id.bin, id_bin);
+
+static struct attribute *uid_attrs[] = {
+ &id_attr.attr,
+ &id_bin_attr.attr,
+ NULL
+};
+
+static struct attribute_group uid_attr_group = {
+ .attrs = uid_attrs,
+};
+
+struct kobject *uid_provider_init(const char *name,
+ struct uid_ops *ops, void *context)
+{
+ struct uid_provider *new;
+ int err;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ new->kobj = kobject_create_and_add(name, uid_kobj);
+ if (!new->kobj) {
+ err = -ENOMEM;
+ goto out;
+ }
+ new->ops = ops;
+ new->context = context;
+
+ err = sysfs_create_group(new->kobj, &uid_attr_group);
+ if (err)
+ goto out2;
+
+ list_add_tail(&new->list, &uid_provider_list);
+ return new->kobj;
+out2:
+ kobject_del(new->kobj);
+out:
+ kfree(new);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(uid_provider_init);
+
+static struct uid_provider *uid_provider_find(const char *name)
+{
+ struct uid_provider *p;
+
+ list_for_each_entry(p, &uid_provider_list, list) {
+ if (strcmp(kobject_name(p->kobj), name) == 0)
+ return p;
+ }
+ return NULL;
+}
+
+void uid_provider_remove(const char *name)
+{
+ struct uid_provider *p;
+
+ p = uid_provider_find(name);
+ if (!p)
+ return;
+ kobject_del(p->kobj);
+ list_del(&p->list);
+ kfree(p);
+}
+EXPORT_SYMBOL_GPL(uid_provider_remove);
+
+static int uid_sysfs_init(void)
+{
+ int error;
+
+ uid_kobj = kobject_create_and_add("uid", NULL);
+ if (!uid_kobj) {
+ error = -ENOMEM;
+ goto out1;
+ }
+
+ spin_lock_init(&u_lock);
+ setup_timer(&u_timer, uid_timer_autolock, (unsigned long)&u_timer);
+
+ /* try to lock each 3 minutes */
+ mod_timer(&u_timer, jiffies + UID_AUTOLOCK_TIMEOUT);
+ return 0;
+
+out1:
+ printk(KERN_ERR"%s failed, error %d.", __func__, error);
+ return error;
+}
+
+module_param(unlock, int, 0600)
+core_initcall(uid_sysfs_init);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>");
+MODULE_DESCRIPTION("Unique ID simple framework");