zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297510/pcu.c b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297510/pcu.c
new file mode 100644
index 0000000..07d0522
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297510/pcu.c
@@ -0,0 +1,331 @@
+/*
+ * linux/arch/arm/mach-zx297510/pcu.c
+ *
+ * Copyright (C) 2013 ZTE-TSP
+ *
+ * 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 <linux/errno.h>
+ #include <linux/irq.h>
+ #include <linux/module.h>
+ 
+ #include <asm/io.h>
+ 
+ #include <mach/iomap.h>
+ #include <mach/zx-pm.h> 
+ #include <mach/zx297510-pm.h>
+ #include <mach/pcu.h>
+ #include <mach/spinlock.h>
+ 
+/*
+ * return external intterrupt  number from ex8-ex15,
+ * return value is 8-15
+ */
+unsigned int pcu_int_vector_8in1(void)
+{  
+	void __iomem *reg_base = EX_INT_VECTOR_REG;
+	unsigned int vector_8in1 = 0;
+ 
+	vector_8in1 = ioread32(reg_base);	 
+	
+	return 	((vector_8in1&0x7) + 8);
+}
+EXPORT_SYMBOL(pcu_int_vector_8in1);  
+
+ 
+
+/*external int 8-15 need extra clear*/
+ void pcu_int_clear_8in1(PCU_INT_INDEX index)
+ {	
+	void __iomem *reg_base = EX_INT_TOP_CLEAR_REG;
+	unsigned int vector=0;
+	
+	if ( (index >= PCU_EX8_INT)&&(index <= PCU_EX15_INT) ){
+	/*
+	 *in 7510 platform, 8in1 interrupt would be used by different cores.
+	 *when any core installs a new 8in1 interrupt, another core may be 
+	 * responding another 8in1 interrupt, so  8in1 interrupt shouldn't be 
+	 *cleared. in this case, nothing to be done. but a new problem comes,
+	 * the core install new  8in1 interrupt will receive a fake interrupt.
+	 */
+		vector=pcu_int_vector_8in1();
+		if (index != (vector + PCU_EX0_INT) )  
+			return;
+		
+		reg_spin_lock();
+   		iowrite32(0x1,reg_base);
+		reg_spin_unlock();
+   }
+ }
+EXPORT_SYMBOL(pcu_int_clear_8in1); 
+
+/*only pulse int need be clear*/
+ void pcu_int_clear(PCU_INT_INDEX index)
+ {
+ 	unsigned int reg_num = index&0x100;
+	unsigned int bit_mask = 1<<(index&0x1f);
+	void __iomem *reg_base = NULL;
+	unsigned int tmp;
+	
+	if (reg_num == 0x100)
+        reg_base = PCU_BASE_VA + 0xec;
+	else
+		reg_base = PCU_BASE_VA + 0x80;
+
+	reg_spin_lock();
+	tmp = ioread32(reg_base);
+	tmp |= bit_mask;     
+	iowrite32(tmp,reg_base);
+	reg_spin_unlock();
+
+	pcu_int_clear_8in1(index);
+ }
+EXPORT_SYMBOL(pcu_int_clear);
+
+
+void pcu_int_set_type(PCU_INT_INDEX index,unsigned int type)
+{
+    unsigned int reg_num = index&0x100;
+	unsigned int bit_index = index&0x1f;
+	unsigned int bit_mask = 1<<bit_index;
+	
+	void __iomem *level_regbase = NULL;
+	void __iomem *pol_regbase = NULL;
+	unsigned int tmp;
+	unsigned int level;
+	unsigned int pol;
+
+    if (reg_num == 0x100){
+        level_regbase = PCU_BASE_VA + 0xe4;
+		pol_regbase = PCU_BASE_VA + 0xe8;
+    }	
+	else{
+		level_regbase = PCU_BASE_VA + 0x60;
+		pol_regbase = PCU_BASE_VA + 0x70;
+	}	
+    
+	
+	switch (type) {
+		case IRQ_TYPE_LEVEL_HIGH:
+			level = 1;
+			pol = 1;
+			break;
+		case IRQ_TYPE_EDGE_RISING:
+			level = 0;
+			pol = 1;
+			break;
+		case IRQ_TYPE_LEVEL_LOW:		
+			level = 1;
+			pol= 0;
+			break;
+		case IRQ_TYPE_EDGE_FALLING:		
+			level = 0;
+			pol = 0;
+			break;
+		default:
+			BUG();
+	}
+	
+	reg_spin_lock();
+    /* set level*/
+	tmp = ioread32(level_regbase);
+	tmp &= ~bit_mask; 
+	tmp |= level<<bit_index;
+	iowrite32(tmp,level_regbase);
+
+	/* set polarity */
+	tmp = ioread32(pol_regbase);
+	tmp &= ~bit_mask;
+	tmp |= pol<<bit_index;
+	iowrite32(tmp,pol_regbase);	
+	reg_spin_unlock();
+	
+}	
+EXPORT_SYMBOL(pcu_int_set_type);
+
+
+
+/* low power function */
+   
+extern unsigned int wake_source_int_for_suspend[];
+extern unsigned int wake_source_int_for_dpidle[];
+/**
+ * enable wake source for cpu
+ * 
+ */
+static void pcu_enable_wake_source(unsigned int *wake_source)
+{
+	unsigned int int1, int2, int_timer;
+
+	int1 		= wake_source[0];
+	int2 		= wake_source[1];
+	int_timer 	= wake_source[2];
+
+	reg_spin_lock();
+
+	pm_clr_reg(AP_INT_WAKE_DIS_REG1, int1);
+	pm_clr_reg(AP_INT_WAKE_DIS_REG2, int2);
+	pm_clr_reg(TIMER_INT_WAKE_DIS_REG, int_timer);	
+
+	reg_spin_unlock();	
+}
+
+static void pcu_set_wake_source(cpu_sleep_type_t sleep_type)
+{
+	if(CPU_SLEEP_TYPE_LP1 == sleep_type)
+	{ 
+		pcu_enable_wake_source(wake_source_int_for_suspend);
+	}
+	else if(CPU_SLEEP_TYPE_IDLE_LP2 == sleep_type || CPU_SLEEP_TYPE_LP3 == sleep_type)
+	{
+		pcu_enable_wake_source(wake_source_int_for_dpidle);
+	}
+}
+
+/**
+ * init pcu when pm initial.
+ * 
+ */
+void zx297510_pcu_init(void)
+{
+    pr_info("[SLP] Power/PCU_INIT \n");
+
+	pm_clr_reg(ARM_AP_CONFIG_REG, PCU_MODE_MASK);
+	pm_set_pll_used();
+	pm_set_reg(ARM_AP_SLEEP_TIME_REG, PCU_AP_SLEEP_TIME_DIS);
+
+	pm_write_reg(AP_L2_POWER_ENABLE_REG, 0);		
+
+	pm_write_reg(AP_INT_WAKE_DIS_REG1, 0xFFFFFFFF);
+	pm_write_reg(AP_INT_WAKE_DIS_REG2, 0xFFFFFFFF);
+
+	pm_set_reg(AP_LOW_POWER_REG1, 0);            /* bypass disable */
+	pm_set_reg(AP_LOW_POWER_REG2, 0);            /* 1 - enter DS  0 - exit DS */	
+}
+
+/**
+ * set&enable PCU for interrupt/clock/powerdomain/pll/iram.
+ * 
+ */
+int zx297510_set_pcu(void)
+{
+	cpu_sleep_type_t sleep_type;
+	u32	sleep_time;
+
+	sleep_type 	= pm_get_sleep_type();
+	sleep_time	= pm_get_sleep_time();
+
+	pm_set_pll_used();	
+
+	if(CPU_SLEEP_TYPE_LP1 == sleep_type)	/* shutdown */
+	{ 
+		pm_set_reg(ARM_AP_CONFIG_REG, PCU_SHUTDOWN_MODE);
+		pm_set_reg(ARM_AP_CONFIG_REG, PCU_MG_CLK_RESET|PCU_L2_CLK_GATE|PCU_PLL_OFF);
+		
+		pm_write_reg(ARM_AP_SLEEP_TIME_REG, 0xffffffff);
+
+		pm_write_reg(AP_L2_POWER_ENABLE_REG, 1);
+
+	}
+	else if(CPU_SLEEP_TYPE_IDLE_LP2 == sleep_type)	/* dormant */
+	{
+		pm_set_reg(ARM_AP_CONFIG_REG, PCU_DORMANT_MODE);
+		pm_set_reg(ARM_AP_CONFIG_REG, PCU_MG_CLK_RESET|PCU_L2_CLK_GATE|PCU_PLL_OFF);
+
+		pm_write_reg(ARM_AP_SLEEP_TIME_REG, sleep_time);
+	}
+	else if(CPU_SLEEP_TYPE_LP3 == sleep_type)
+	{
+		pm_set_reg(ARM_AP_CONFIG_REG, PCU_STANDBY_MODE);
+		pm_clr_reg(ARM_AP_CONFIG_REG, PCU_PLL_OFF);
+		pm_set_reg(ARM_AP_CONFIG_REG, PCU_MG_CLK_RESET|PCU_L2_CLK_GATE);
+		
+		pm_write_reg(ARM_AP_SLEEP_TIME_REG, sleep_time);
+	}
+	else
+		WARN_ON(1);
+
+	pcu_set_wake_source(sleep_type);
+
+	return 0;
+}
+
+/**
+ * clear&disable PCU for interrupt/clock/powerdomain/pll/iram.
+ * 
+ */
+int zx297510_clear_pcu(void)
+{
+	reg_spin_lock();
+
+	pm_clr_reg(ARM_AP_CONFIG_REG, PCU_MODE_MASK);
+
+	pm_write_reg(AP_L2_POWER_ENABLE_REG, 0);	
+
+	pm_write_reg(AP_INT_WAKE_DIS_REG1, 0xFFFFFFFF);
+	pm_write_reg(AP_INT_WAKE_DIS_REG2, 0xFFFFFFFF);
+
+	pm_set_reg(TIMER_INT_WAKE_DIS_REG, WAKE_SRC_TIMER3);
+	
+	reg_spin_unlock();
+	
+	return 0;
+}
+
+/**
+ * when sleep/dormant/poweroff, pll will be closed.
+ * 
+ */
+void pcu_set_pll_used(unsigned pll)
+{
+	if(PCU_USE_PLL_MAIN == pll)
+		pm_clr_reg(ARM_AP_CONFIG_REG, pll);
+	else
+		pm_set_reg(ARM_AP_CONFIG_REG, pll);
+}
+
+/**
+ * get wakeup setting.
+ * 
+ */
+void pcu_get_wakeup_setting(unsigned int *pointer)
+{
+	pointer[0] = pm_read_reg(AP_INT_WAKE_DIS_REG1);
+	pointer[1] = pm_read_reg(AP_INT_WAKE_DIS_REG2);
+	pointer[2] = pm_read_reg(TIMER_INT_WAKE_DIS_REG);	
+}
+
+void pcu_clr_timer3_int(void)
+{
+	reg_spin_lock();
+
+	pm_set_reg(TIMER_INT_DDR_SW_CLEAR_REG, WAKE_SRC_TIMER3);
+
+	reg_spin_unlock();
+}
+
+/**
+ * set wakeup enable.
+ * 
+ * now only support ext_int.
+ */
+void pcu_irq_wakeup(PCU_INT_INDEX index, int enable)
+{
+	if ( (index < PCU_EX0_INT) || (index > PCU_EX15_INT) )
+		return;
+
+	if(enable)
+	{
+		wake_source_int_for_suspend[0] |= (1<<index);
+		wake_source_int_for_dpidle[0]  |= (1<<index);		
+	}		
+	else
+	{
+		wake_source_int_for_suspend[0] &= ~(1<<index);
+		wake_source_int_for_dpidle[0]  &= ~(1<<index);		
+	}
+}
+