From: Anson Huang Date: Mon, 18 Jul 2011 04:54:13 +0000 (+0800) Subject: ENGR00139274-1 [MX6]Enable suspend/resume feature X-Git-Tag: v3.0.35-fsl_4.1.0~2398 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=2d5b0f3b12c61e2742156d2fd09fa306712a6256;p=karo-tx-linux.git ENGR00139274-1 [MX6]Enable suspend/resume feature Enable suspend/resume feature for MX6q echo standby > /sys/power/state -> wait mode; echo mem > /sys/power/state -> stop mode; Currentlu only support debug uart as wakeup source; Signed-off-by: Anson Huang --- diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig index 265439983cb0..5619c7eb1794 100644 --- a/arch/arm/mach-mx6/Kconfig +++ b/arch/arm/mach-mx6/Kconfig @@ -39,6 +39,7 @@ config MACH_MX6Q_SABREAUTO select IMX_HAVE_PLATFORM_IMX_OCOTP select IMX_HAVE_PLATFORM_IMX2_WDT select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM help Include support for i.MX 6Quad SABRE Automotive Infotainment platform. This includes specific configurations for the board and its peripherals. diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile index 99b5623f3fad..094b2cfd7773 100644 --- a/arch/arm/mach-mx6/Makefile +++ b/arch/arm/mach-mx6/Makefile @@ -3,8 +3,8 @@ # # Object file lists. -obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h1.o +obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h1.o pm.o -obj-$(CONFIG_ARCH_MX6) += clock.o +obj-$(CONFIG_ARCH_MX6) += clock.o mx6q_suspend.o obj-$(CONFIG_MACH_MX6Q_SABREAUTO) += board-mx6q_sabreauto.o obj-$(CONFIG_SMP) += plat_hotplug.o platsmp.o headsmp.o localtimer.o diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c index 0b1e967b8802..4bba7a49b0ff 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c @@ -505,6 +505,20 @@ static struct imx_ipuv3_platform_data ipu_data[] = { }, }; +static void sabreauto_suspend_enter(void) +{ + /* suspend preparation */ +} + +static void sabreauto_suspend_exit(void) +{ + /* resmue resore */ +} +static const struct pm_platform_data mx6q_sabreauto_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = sabreauto_suspend_enter, + .suspend_exit = sabreauto_suspend_exit, +}; /*! * Board specific initialization. */ @@ -537,6 +551,7 @@ static void __init mx6_board_init(void) imx6q_add_anatop_thermal_imx(1, &mx6q_sabreauto_anatop_thermal_data); imx6q_init_fec(); + imx6q_add_pm_imx(0, &mx6q_sabreauto_pm_data); imx6q_add_sdhci_usdhc_imx(3, &mx6q_sabreauto_sd4_data); imx6q_add_sdhci_usdhc_imx(2, &mx6q_sabreauto_sd3_data); imx_add_viv_gpu("gc2000", &imx6_gc2000_data, &imx6q_gc2000_pdata); diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c index 685646793dbc..f0e1d77d35ce 100644 --- a/arch/arm/mach-mx6/cpu.c +++ b/arch/arm/mach-mx6/cpu.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h index fe408c60c0d4..488ae599759e 100644 --- a/arch/arm/mach-mx6/devices-imx6q.h +++ b/arch/arm/mach-mx6/devices-imx6q.h @@ -111,3 +111,7 @@ extern const struct imx_otp_data imx6q_otp_data __initconst; extern const struct imx_imx2_wdt_data imx6q_imx2_wdt_data[] __initconst; #define imx6q_add_imx2_wdt(id, pdata) \ imx_add_imx2_wdt(&imx6q_imx2_wdt_data[id]) + +extern const struct imx_pm_imx_data imx6q_pm_imx_data __initconst; +#define imx6q_add_pm_imx(id, pdata) \ + imx_add_pm_imx(&imx6q_pm_imx_data, pdata) diff --git a/arch/arm/mach-mx6/devices.c b/arch/arm/mach-mx6/devices.c index f40b5a4d7456..996de31d4933 100644 --- a/arch/arm/mach-mx6/devices.c +++ b/arch/arm/mach-mx6/devices.c @@ -32,27 +32,6 @@ #include #include -static struct resource mxc_anatop_resources[] = { - { - .start = ANATOP_BASE_ADDR, - .end = ANATOP_BASE_ADDR + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MXC_INT_ANATOP_TEMPSNSR, - .end = MXC_INT_ANATOP_TEMPSNSR, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device anatop_thermal_device = { - .name = "anatop_thermal", - .id = 1, - .num_resources = ARRAY_SIZE(mxc_anatop_resources), - .resource = mxc_anatop_resources, -}; - - static struct mxc_gpio_port mxc_gpio_ports[] = { { .chip.label = "gpio-0", diff --git a/arch/arm/mach-mx6/mx6q_suspend.S b/arch/arm/mach-mx6/mx6q_suspend.S new file mode 100644 index 000000000000..d39ff7ccefbd --- /dev/null +++ b/arch/arm/mach-mx6/mx6q_suspend.S @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#define ARM_CTRL_DCACHE 1 << 2 +#define ARM_CTRL_ICACHE 1 << 12 +#define ARM_AUXCR_L2EN 1 << 1 + +/* + * mx6q_suspend + * + * Suspend the processor (eg, wait for interrupt). + * Set the DDR into Self Refresh + * IRQs are already disabled. + */ +ENTRY(mx6q_suspend) + stmfd sp!, {r0-r4} @ Save registers + dsb + wfi + ldmfd sp!, {r0-r4} + .type mx6q_do_suspend, #object +ENTRY(mx6q_do_suspend) + .word mx6q_suspend + .size mx6q_suspend, . - mx6q_suspend diff --git a/arch/arm/mach-mx6/plat_hotplug.c b/arch/arm/mach-mx6/plat_hotplug.c index a0d94908765c..6ef057f6865a 100644 --- a/arch/arm/mach-mx6/plat_hotplug.c +++ b/arch/arm/mach-mx6/plat_hotplug.c @@ -19,7 +19,11 @@ #include #include #include - +#include +#include +#include +#include "src-reg.h" +#include #include @@ -34,7 +38,30 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { + void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR); + unsigned int val; + + if (cpu == 0) { + printk(KERN_ERR "CPU0 can't be disabled!\n"); + return; + } + flush_cache_all(); + dsb(); + + /* + * we're ready for shutdown now, so do it + */ + val = readl(src_base + SRC_SCR_OFFSET); + val &= ~(1 << (BP_SRC_SCR_CORES_DBG_RST + cpu)); + writel(val, src_base + SRC_SCR_OFFSET); + for (;;) { + /* + * Execute WFI + */ + cpu_do_idle(); + printk(KERN_INFO "CPU%u: spurious wakeup call\n", cpu); + } } int platform_cpu_disable(unsigned int cpu) diff --git a/arch/arm/mach-mx6/platsmp.c b/arch/arm/mach-mx6/platsmp.c index a49e3cca3cc4..66ab4e60dfe2 100644 --- a/arch/arm/mach-mx6/platsmp.c +++ b/arch/arm/mach-mx6/platsmp.c @@ -61,7 +61,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long boot_entry; void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR); - unsigned long timeout; int val; /* diff --git a/arch/arm/mach-mx6/pm.c b/arch/arm/mach-mx6/pm.c new file mode 100644 index 000000000000..0d30bdf9500d --- /dev/null +++ b/arch/arm/mach-mx6/pm.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2011 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ARCH_MX61 +#include +#endif +#include "crm_regs.h" + +#define SCU_CTRL_OFFSET 0x00 +#define GPC_IMR1_OFFSET 0x08 +#define GPC_IMR2_OFFSET 0x0c +#define GPC_IMR3_OFFSET 0x10 +#define GPC_IMR4_OFFSET 0x14 +#define GPC_PGC_CPU_PUPSCR_OFFSET 0x2a4 +#define GPC_PGC_CPU_PDNSCR_OFFSET 0x2a8 +#define UART_UCR3_OFFSET 0x88 +#define UART_USR1_OFFSET 0x94 +#define UART_UCR3_AWAKEN (1 << 4) +#define UART_USR1_AWAKE (1 << 4) +static struct clk *cpu_clk; +static struct pm_platform_data *pm_data; + +#if defined(CONFIG_CPU_FREQ) +static int org_freq; +extern int set_cpu_freq(int wp); +#endif + +extern void mx6q_suspend(u32 m4if_addr); +static struct device *pm_dev; +struct clk *gpc_dvfs_clk; +void *suspend_iram_base; +void (*suspend_in_iram)(void *sdclk_iomux_addr) = NULL; +void __iomem *suspend_param1; + +static void __iomem *scu_base; +static void __iomem *gpc_base; +static u32 ccm_clpcr, scu_ctrl; +static u32 gpc_imr[4], gpc_cpu_pup, gpc_cpu_pdn; + +static void mx6_suspend_store() +{ + /* save some settings before suspend */ + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR); + scu_ctrl = __raw_readl(scu_base + SCU_CTRL_OFFSET); + gpc_imr[0] = __raw_readl(gpc_base + GPC_IMR1_OFFSET); + gpc_imr[1] = __raw_readl(gpc_base + GPC_IMR2_OFFSET); + gpc_imr[2] = __raw_readl(gpc_base + GPC_IMR3_OFFSET); + gpc_imr[3] = __raw_readl(gpc_base + GPC_IMR4_OFFSET); + gpc_cpu_pup = __raw_readl(gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); + gpc_cpu_pdn = __raw_readl(gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); +} + +static void mx6_suspend_restore() +{ + /* restore settings after suspend */ + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + __raw_writel(scu_ctrl, scu_base + SCU_CTRL_OFFSET); + __raw_writel(gpc_imr[0], gpc_base + GPC_IMR1_OFFSET); + __raw_writel(gpc_imr[1], gpc_base + GPC_IMR2_OFFSET); + __raw_writel(gpc_imr[2], gpc_base + GPC_IMR3_OFFSET); + __raw_writel(gpc_imr[3], gpc_base + GPC_IMR4_OFFSET); + __raw_writel(gpc_cpu_pup, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); + __raw_writel(gpc_cpu_pdn, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); +} +static int mx6_suspend_enter(suspend_state_t state) +{ + mx6_suspend_store(); + + switch (state) { + case PM_SUSPEND_MEM: + mxc_cpu_lp_set(STOP_POWER_OFF); + break; + case PM_SUSPEND_STANDBY: + mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + break; + default: + return -EINVAL; + } + + if (state == PM_SUSPEND_MEM) { + if (pm_data && pm_data->suspend_enter) + pm_data->suspend_enter(); + + local_flush_tlb_all(); + flush_cache_all(); + outer_cache.flush_all(); + + suspend_in_iram(suspend_param1); + + mx6_suspend_restore(); + if (pm_data && pm_data->suspend_exit) + pm_data->suspend_exit(); + } else { + cpu_do_idle(); + } + return 0; +} + + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int mx6_suspend_prepare(void) +{ + return 0; +} + +/* + * Called before devices are re-setup. + */ +static void mx6_suspend_finish(void) +{ +#if defined(CONFIG_CPU_FREQ) + struct cpufreq_freqs freqs; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = org_freq / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + if (org_freq != clk_get_rate(cpu_clk)) { + set_cpu_freq(org_freq); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } +#endif +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static void mx6_suspend_end(void) +{ +} + +static int mx6_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + +struct platform_suspend_ops mx6_suspend_ops = { + .valid = mx6_pm_valid, + .prepare = mx6_suspend_prepare, + .enter = mx6_suspend_enter, + .finish = mx6_suspend_finish, + .end = mx6_suspend_end, +}; + +static int __devinit mx6_pm_probe(struct platform_device *pdev) +{ + pm_dev = &pdev->dev; + pm_data = pdev->dev.platform_data; + + return 0; +} + +static struct platform_driver mx6_pm_driver = { + .driver = { + .name = "imx_pm", + }, + .probe = mx6_pm_probe, +}; + +static int __init pm_init(void) +{ + unsigned long iram_paddr, cpaddr; + + scu_base = IO_ADDRESS(SCU_BASE_ADDR); + gpc_base = IO_ADDRESS(GPC_BASE_ADDR); + + pr_info("Static Power Management for Freescale i.MX6\n"); + + if (platform_driver_register(&mx6_pm_driver) != 0) { + printk(KERN_ERR "mx6_pm_driver register failed\n"); + return -ENODEV; + } + + suspend_set_ops(&mx6_suspend_ops); + /* Move suspend routine into iRAM */ + cpaddr = (unsigned long)iram_alloc(SZ_4K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + suspend_iram_base = __arm_ioremap(iram_paddr, SZ_4K, + MT_HIGH_VECTORS); + pr_info("cpaddr = %x suspend_iram_base=%x\n", + (unsigned int)cpaddr, (unsigned int)suspend_iram_base); + + /* + * Need to run the suspend code from IRAM as the DDR needs + * to be put into self refresh mode manually. + */ + memcpy((void *)cpaddr, mx6q_suspend, SZ_4K); + + suspend_in_iram = (void *)suspend_iram_base; + + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_DEBUG "%s: failed to get cpu_clk\n", __func__); + return PTR_ERR(cpu_clk); + } + printk(KERN_INFO "PM driver module loaded\n"); + + return 0; +} + + +static void __exit pm_cleanup(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&mx6_pm_driver); +} + +module_init(pm_init); +module_exit(pm_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("PM driver"); +MODULE_LICENSE("GPL"); + diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c index ba4091e9d285..f18389bf26da 100644 --- a/arch/arm/mach-mx6/system.c +++ b/arch/arm/mach-mx6/system.c @@ -26,6 +26,86 @@ #include #include #include +#include "crm_regs.h" + +#define SCU_CTRL 0x00 +#define SCU_CONFIG 0x04 +#define SCU_CPU_STATUS 0x08 +#define SCU_INVALIDATE 0x0c +#define SCU_FPGA_REVISION 0x10 + +void gpc_enable_wakeup(unsigned int irq) +{ + void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); + + if ((irq < 32) || (irq > 158)) + printk(KERN_ERR "Invalid irq number!\n"); + + /* Enable wake up source */ + __raw_writel(~(1 << (irq % 32)), + gpc_base + 0x8 + (irq / 32 - 1) * 4); + +} +/* set cpu low power mode before WFI instruction */ +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) +{ + void __iomem *scu_base = IO_ADDRESS(SCU_BASE_ADDR); + void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); + u32 scu_cr, ccm_clpcr; + int stop_mode = 0; + + scu_cr = __raw_readl(scu_base + SCU_CTRL); + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); + + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET; + break; + case WAIT_UNCLOCKED_POWER_OFF: + case STOP_POWER_OFF: + if (mode == WAIT_UNCLOCKED_POWER_OFF) { + ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET; + ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + stop_mode = 0; + } else { + ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET; + ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET; + ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; + ccm_clpcr |= MXC_CCM_CLPCR_SBYOS; + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS; + stop_mode = 1; + } + /* scu standby enable, scu clk will be + * off after all cpu enter WFI */ + scu_cr |= 0x20; + break; + case STOP_POWER_ON: + ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET; + break; + default: + printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode); + return; + } + + if (stop_mode == 1) { + /* Mask all wake up source */ + __raw_writel(0xFFFFFFFF, gpc_base + 0x8); + __raw_writel(0xFFFFFFFF, gpc_base + 0xC); + __raw_writel(0xFFFFFFFF, gpc_base + 0x10); + __raw_writel(0xFFFFFFFF, gpc_base + 0x14); + /* Power down and power up sequence */ + __raw_writel(0xFFFFFFFF, gpc_base + 0x2a4); + __raw_writel(0xFFFFFFFF, gpc_base + 0x2a8); + + gpc_enable_wakeup(MXC_INT_UART4_ANDED); + } + + __raw_writel(scu_cr, scu_base + SCU_CTRL); + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); +} void arch_idle(void) { diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index 1307a4aaf06b..7c0e691277b1 100755 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -145,3 +145,6 @@ config IMX_HAVE_PLATFORM_FSL_OTG config IMX_HAVE_PLATFORM_FSL_USB_WAKEUP bool + +config IMX_HAVE_PLATFORM_IMX_PM + bool diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index 43db7417c1bd..ff11fa946fee 100755 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -50,3 +50,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_VIV_GPU) += platform-viv_gpu.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL) += platform-imx-anatop-thermal.o obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_OTG) += platform-fsl-usb2-otg.o obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB_WAKEUP) += platform-fsl-usb2-wakeup.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_PM) += platform-imx-pm.o diff --git a/arch/arm/plat-mxc/devices/platform-imx-pm.c b/arch/arm/plat-mxc/devices/platform-imx-pm.c new file mode 100644 index 000000000000..f901e18368c2 --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-imx-pm.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include +#include +#include + +#define imx_pm_imx_data_entry_single(soc) \ + { \ + } + +#ifdef CONFIG_SOC_IMX6Q +const struct imx_pm_imx_data imx6q_pm_imx_data[] __initconst = + imx_pm_imx_data_entry_single(MX6Q); +#endif + +struct platform_device *__init imx_add_pm_imx( + const struct imx_pm_imx_data *data, + const struct pm_platform_data *pdata) +{ + struct resource res[] = { + { + .start = data->iobase, + .end = data->iobase + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + }; + + return imx_add_platform_device("imx_pm", 0, + res, ARRAY_SIZE(res), pdata, sizeof(*pdata)); +} diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index b37e876fc8ec..213e05c446f9 100755 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -503,6 +503,16 @@ struct imx_dcp_data { resource_size_t irq2; }; + +#include +struct imx_pm_imx_data { + int id; + resource_size_t iobase; + resource_size_t irq; +}; +struct platform_device *__init imx_add_pm_imx( + const struct imx_pm_imx_data *data, + const struct pm_platform_data *pdata); struct platform_device *__init imx_add_dcp( struct imx_fsl_usb2_otg_data { diff --git a/arch/arm/plat-mxc/include/mach/imx-pm.h b/arch/arm/plat-mxc/include/mach/imx-pm.h new file mode 100644 index 000000000000..f6d375a4f575 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/imx-pm.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __ASM_ARCH_IMX_PM_H +#define __ASM_ARCH_IMX_PM_H + +/** + * struct pm_platform_data - optional platform data for pm on i.MX + * + */ + +struct pm_platform_data { + char *name; + void (*suspend_enter) (void); + void (*suspend_exit) (void); +}; +#endif /* __ASM_ARCH_IMX_PM_H */