ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/arch/arm/mach-mmp/pm.c b/marvell/linux/arch/arm/mach-mmp/pm.c
new file mode 100644
index 0000000..437c3d8
--- /dev/null
+++ b/marvell/linux/arch/arm/mach-mmp/pm.c
@@ -0,0 +1,166 @@
+/*
+ * linux/arch/arm/mach-mmp/pm.c
+ *
+ * Author:      Fan Wu <fwu@marvell.com>
+ * Copyright:   (C) 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <asm/cputype.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/mcpm.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <soc/asr/asr18xx_lowpower.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/mmp.h>
+#include <linux/cpu_pm.h>
+#include "irqs.h"
+#include "pm.h"
+#include <soc/asr/mmp_cpuidle.h>
+
+struct platform_suspend *mmp_suspend;
+u32 detect_wakeup_status = 0;
+EXPORT_SYMBOL(detect_wakeup_status);
+
+#if !defined(CONFIG_CPU_ASR18XX)
+static int notrace mcpm_powerdown_finisher(unsigned long arg)
+{
+	u32 mpidr = read_cpuid_mpidr();
+	u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	u32 this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	mcpm_set_entry_vector(cpu, this_cluster, cpu_resume);
+
+	asr_set_target_lpm_state(cpu, this_cluster, *((int *)arg), (int *)arg);
+
+	mcpm_cpu_suspend();
+	return 1;
+}
+#endif
+
+#if defined(CONFIG_CPU_ASR18XX)
+extern void asr18xx_pm_power_down(void);
+extern void asr18xx_pm_powered_up(void);
+extern void asr18xx_dcstat(unsigned long addr, unsigned int flag);
+extern int asr18xx_pm_check_constraint(void);
+static int notrace mmp_suspend_finish(unsigned long val)
+{
+	asr18xx_pm_power_down();
+	return 1;
+}
+#endif
+
+static int mmp_pm_enter(suspend_state_t state)
+{
+	unsigned int real_idx = mmp_suspend->suspend_state;
+
+	if (mmp_suspend->ops->pre_suspend_check) {
+		if (mmp_suspend->ops->pre_suspend_check())
+			return -EAGAIN;
+	}
+#if !defined(CONFIG_CPU_ASR18XX)
+	cpu_suspend((unsigned long)&real_idx, mcpm_powerdown_finisher);
+#else
+	cpu_suspend((unsigned long)&real_idx, mmp_suspend_finish);
+#endif
+	if (mmp_suspend->ops->post_chk_wakeup)
+		detect_wakeup_status = mmp_suspend->ops->post_chk_wakeup();
+
+	if (mmp_suspend->ops->post_clr_wakeup)
+		mmp_suspend->ops->post_clr_wakeup(detect_wakeup_status);
+
+	if (real_idx != mmp_suspend->suspend_state)
+		pr_info("WARNING!!! "
+			"Suspend Didn't enter the Expected Low power mode\n");
+#if !defined(CONFIG_CPU_ASR18XX)
+	mcpm_cpu_powered_up();
+#else
+	asr18xx_pm_powered_up();
+#endif
+	return 0;
+}
+
+static int mmp_pm_valid(suspend_state_t state)
+{
+	return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+extern void asr_clear_wakeup_event_idx(void);
+/* Called after devices suspend, before noirq devices suspend */
+static int mmp_pm_prepare(void)
+{
+#ifdef CONFIG_CPU_ASR18XX
+	asr18xx_dcstat(0, 0);
+#endif
+	asr_clear_wakeup_event_idx();
+	return 0;
+}
+
+/* Called after noirq devices resume, before devices resume */
+static void mmp_pm_finish(void)
+{
+}
+
+/* Called after Non-boot CPUs have been Hotplug in if necessary */
+static void mmp_pm_wake(void)
+{
+}
+
+static const struct platform_suspend_ops mmp_pm_ops = {
+	.valid          = mmp_pm_valid,
+	.prepare        = mmp_pm_prepare,
+	.enter          = mmp_pm_enter,
+	.finish         = mmp_pm_finish,
+	.wake           = mmp_pm_wake,
+};
+
+int mmp_set_wake(struct irq_data *data, unsigned int on)
+{
+	int irq = (int)data->hwirq;
+	struct irq_desc *desc = irq_to_desc(data->irq);
+
+	if (!mmp_suspend->ops->set_wake) {
+		WARN_ON("Platform set_wake function is not Existed!!");
+		return -EINVAL;
+	}
+	if (!desc) {
+		pr_err("irq_desc is NULL\n");
+		return -EINVAL;
+	}
+	if (on) {
+		if (desc->action)
+			desc->action->flags |= IRQF_NO_SUSPEND;
+	} else {
+		if (desc->action)
+			desc->action->flags &= ~IRQF_NO_SUSPEND;
+	}
+
+	mmp_suspend->ops->set_wake(irq, on);
+
+	return 0;
+}
+
+int __init mmp_platform_suspend_register(struct platform_suspend *plt_suspend)
+{
+	if (mmp_suspend)
+		return -EBUSY;
+
+	mmp_suspend = plt_suspend;
+
+	suspend_set_ops(&mmp_pm_ops);
+#ifndef CONFIG_CPU_ASR18XX
+	gic_arch_extn.irq_set_wake = mmp_set_wake;
+#else
+	icu_irq_chip.irq_set_wake = mmp_set_wake;
+#endif
+	if (mmp_suspend->ops->plt_suspend_init)
+		mmp_suspend->ops->plt_suspend_init();
+
+	return 0;
+}