[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/os/linux/linux-3.4.x/drivers/mfd/zx234290-irq.c b/ap/os/linux/linux-3.4.x/drivers/mfd/zx234290-irq.c
new file mode 100644
index 0000000..14980d8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/mfd/zx234290-irq.c
@@ -0,0 +1,356 @@
+/*
+ * zx234290-irq.c  --  Interrupt controller support for ZX234290 PMICs
+ *
+ * Copyright 2016 ZTE Inc.
+ *
+ * Author: yuxiang<yu.xiang5@zte.com.cn>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mfd/zx234290.h>
+#include <mach/pcu.h>
+#include <mach/gpio.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+
+#define	INT_LOW_LEVEL 	/* yuxiang */
+#define	ZX234290_INT_DEBUG
+#ifdef ZX234290_INT_DEBUG
+unsigned long int_irq_times = 0;
+unsigned long int_thread_times = 0;
+#endif
+struct semaphore zx234290_sem;
+
+#define ZX234290_WAKELOCK 1
+#ifdef ZX234290_WAKELOCK
+#include <linux/wakelock.h>
+static struct wake_lock zx234290_wake_lock;
+#endif
+
+#ifdef ZX234290_PWR_FAUL_PROCESS
+extern int zx234290_regulator_error_irq_request(struct zx234290 *zx234290);
+#endif
+
+static inline int irq_to_zx234290_irq(struct zx234290 *zx234290,
+							int irq)
+{
+	return irq - zx234290->irq_base;
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since the
+ * IRQ handler explicitly clears the IRQ it handles the IRQ line
+ * will be reasserted and the physical IRQ will be handled again if
+ * another interrupt is asserted while we run - in the normal course
+ * of events this is a rare occurrence so we save I2C/SPI reads. We're
+ * also assuming that it's rare to get lots of interrupts firing
+ * simultaneously so try to minimise I/O.
+ */
+static int zx234290_irq(void *irq_data)
+{
+	struct zx234290 *zx234290 = irq_data;
+	u32 irq_sts;
+	u32 irq_mask;
+	u8 buck_sts=0, buck_mask=0;
+	u8 ldo_sts=0, ldo_mask=0;
+	u8 reg;
+	int i;
+	int irq = zx234290->chip_irq;
+
+	const struct sched_param param = {
+		.sched_priority = 31,
+	};
+	sched_setscheduler(current, SCHED_FIFO, &param);
+
+	while (!kthread_should_stop()) {
+		down(&zx234290_sem);
+	#ifdef ZX234290_WAKELOCK
+    	wake_lock(&zx234290_wake_lock);
+	#endif
+
+#ifdef ZX234290_INT_DEBUG
+	int_thread_times ++;
+#endif
+    //printk(KERN_INFO "zx234290 irq  handler:irq=%d.\n", irq);
+
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+	irq_sts = reg;
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTB, 1, &reg);
+	irq_sts |= reg << 8;
+
+ //   printk(KERN_INFO "zx234290 irq  handler:irq=%d, INTR_A=0x%02x, INTR_B=0x%02x\n", irq, irq_sts&0xFF, irq_sts>>8);
+
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTA_MASK, 1, &reg);
+	irq_mask = reg;
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTB_MASK, 1, &reg);
+	irq_mask |= reg << 8;
+
+	irq_sts &= ~irq_mask;	/* 	*/
+
+#ifdef ZX234290_PWR_FAUL_PROCESS
+//++
+	zx234290->read(zx234290, ZX234290_REG_ADDR_BUCK_FAULT_STATUS, 1, &buck_sts);
+	zx234290->read(zx234290, ZX234290_REG_ADDR_LDO_FAULT_STATUS, 1, &ldo_sts);
+	zx234290->read(zx234290, ZX234290_REG_ADDR_BUCK_INT_MASK, 1, &buck_mask);
+	zx234290->read(zx234290, ZX234290_REG_ADDR_LDO_INT_MASK, 1, &ldo_mask);
+
+	buck_sts &= ~buck_mask;
+	ldo_sts &= ~ldo_mask;
+
+	if(buck_sts )
+		irq_sts |= (1 << ZX234290_INT_BUCK_FAUL);
+	else
+		irq_sts &= ~(1 << ZX234290_INT_BUCK_FAUL);
+
+	if(ldo_sts )
+		irq_sts |= (1 << ZX234290_INT_LDO_FAUL);
+	else
+		irq_sts &= ~(1 << ZX234290_INT_LDO_FAUL);
+
+//	if(buck_sts ||  ldo_sts)
+//		printk(KERN_INFO "zx234290 irq  handler:buck_sts=0x%02x, ldo_sts=0x%02x, irq_sts=0x%x\n", buck_sts, ldo_sts, irq_sts);
+#endif
+
+	if (!irq_sts)
+	{
+
+		#ifdef ZX234290_WAKELOCK
+			wake_unlock(&zx234290_wake_lock);
+		#endif
+
+		#ifdef INT_LOW_LEVEL
+			pcu_clr_irq_pending(irq);
+			enable_irq(irq);//yx
+		#endif
+			//return IRQ_NONE;
+			continue;
+	}
+
+	for (i = 0; i < zx234290->irq_num; i++) {
+		if (!(irq_sts & (1 << i)))
+			continue;
+
+		handle_nested_irq(zx234290->irq_base + i);
+	}
+    /*write bit7 to be 0, clear pmu INT*/
+    //zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+    //reg &= ~(0x1<<7);
+    //zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+    #if 0
+	/* Write the STS register back to clear IRQs we handled */
+	reg = irq_sts & 0xFF;
+	irq_sts >>= 8;
+	if (reg)
+		zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+	reg = irq_sts & 0xFF;
+	irq_sts >>= 8;
+	if (reg)
+		zx234290->write(zx234290, ZX234290_REG_ADDR_INTB, 1, &reg);
+    #endif
+
+	#ifdef ZX234290_WAKELOCK
+		wake_unlock(&zx234290_wake_lock);
+	#endif
+
+
+#ifdef INT_LOW_LEVEL
+		pcu_clr_irq_pending(irq);
+		enable_irq(irq);//yx
+#endif
+	}
+	return 0;
+}
+
+static void zx234290_irq_lock(struct irq_data *data)
+{
+	struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&zx234290->irq_lock);
+}
+
+static void zx234290_irq_sync_unlock(struct irq_data *data)
+{
+	struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data);
+	u32 reg_mask;
+	u8 reg, reg2;
+
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTA_MASK, 1, &reg);
+	reg_mask = reg;
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTB_MASK, 1, &reg);
+	reg_mask |= reg << 8;
+	/* take ldo6 & ldo8 error as buck error */
+	zx234290->read(zx234290, ZX234290_REG_ADDR_BUCK_INT_MASK, 1, &reg);
+	if (reg)
+		reg_mask |= BIT(ZX234290_INT_BUCK_FAUL);
+	zx234290->read(zx234290, ZX234290_REG_ADDR_LDO_INT_MASK, 1, &reg);
+	if (reg)
+		reg_mask |= BIT(ZX234290_INT_LDO_FAUL);
+
+	if (zx234290->irq_mask != reg_mask) {
+		reg = zx234290->irq_mask & 0xFC;
+		zx234290->write(zx234290, ZX234290_REG_ADDR_INTA_MASK, 1, &reg);
+
+		reg = zx234290->irq_mask >> 8 & 0xFF;
+		zx234290->write(zx234290, ZX234290_REG_ADDR_INTB_MASK, 1, &reg);
+
+		reg = (zx234290->irq_mask & BIT(ZX234290_INT_BUCK_FAUL)) ? 0xFF : 0;
+		zx234290->write(zx234290, ZX234290_REG_ADDR_BUCK_INT_MASK, 1, &reg);
+
+		reg = (zx234290->irq_mask & BIT(ZX234290_INT_LDO_FAUL)) ? 0xFF : 0;
+		zx234290->write(zx234290, ZX234290_REG_ADDR_LDO_INT_MASK, 1, &reg);
+	}
+
+	mutex_unlock(&zx234290->irq_lock);
+}
+
+static void zx234290_irq_enable(struct irq_data *data)
+{
+	struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data);
+
+	zx234290->irq_mask &= ~(1 << irq_to_zx234290_irq(zx234290, data->irq));
+}
+
+static void zx234290_irq_disable(struct irq_data *data)
+{
+	struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data);
+
+	zx234290->irq_mask |= (1 << irq_to_zx234290_irq(zx234290, data->irq));
+}
+
+static struct irq_chip zx234290_irq_chip = {
+	.name = "zx234290",
+	.irq_bus_lock = zx234290_irq_lock,
+	.irq_bus_sync_unlock = zx234290_irq_sync_unlock,
+	.irq_disable = zx234290_irq_disable,
+	.irq_enable = zx234290_irq_enable,
+};
+static irqreturn_t irq_primary_handler(int irq, void *dev_id)
+{
+#ifdef INT_LOW_LEVEL
+    disable_irq_nosync(irq);//yx
+#endif
+	//pcu_int_clear(PCU_EX0_INT); //xzg
+	pcu_clr_irq_pending(irq);
+	up(&zx234290_sem);
+#ifdef ZX234290_INT_DEBUG
+	int_irq_times ++;
+#endif
+
+	//return IRQ_WAKE_THREAD;
+	return IRQ_HANDLED;
+}
+
+int zx234290_irq_init(struct zx234290 *zx234290, int irq,
+			    struct zx234290_board *pdata)
+{
+	int ret, cur_irq;
+/*	int flags = IRQF_ONESHOT; */
+	u8 reg;
+
+	#ifdef ZX234290_WAKELOCK
+    	wake_lock_init(&zx234290_wake_lock, WAKE_LOCK_SUSPEND, "zx234290");
+	#endif
+
+	if (!irq) {
+		dev_warn(zx234290->dev, "No interrupt support, no core IRQ\n");
+		return 0;
+	}
+
+	if (!pdata || !pdata->irq_base) {
+		dev_warn(zx234290->dev, "No interrupt support, no IRQ base\n");
+		return 0;
+	}
+
+	sema_init(&zx234290_sem, 0);
+	/* Clear unattended interrupts */
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+	//zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTB, 1, &reg);
+	//zx234290->write(zx234290, ZX234290_REG_ADDR_INTB, 1, &reg);
+
+	/*write bit7 to be 0, clear pmu INT*/
+	zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+	reg &= ~(0x1<<7);
+	zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, &reg);
+
+	/* Mask top level interrupts */
+	zx234290->irq_mask = 0xFFFF;
+
+	mutex_init(&zx234290->irq_lock);
+	zx234290->chip_irq = irq;				/* irq	*/
+	zx234290->irq_base = pdata->irq_base;	/* irq_base  32+49	*/
+
+	zx234290->irq_num = ZX234290_NUM_IRQ;
+
+	/* Register with genirq */
+	for (cur_irq = zx234290->irq_base;
+	     cur_irq < zx234290->irq_num + zx234290->irq_base;
+	     cur_irq++) {
+		irq_set_chip_data(cur_irq, zx234290);
+		irq_set_chip_and_handler(cur_irq, &zx234290_irq_chip,
+					 handle_edge_irq);
+		irq_set_nested_thread(cur_irq, 1);
+		/* ARM needs us to explicitly flag the IRQ as valid
+		 * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+		set_irq_flags(cur_irq, IRQF_VALID);
+#else
+		irq_set_noprobe(cur_irq);
+#endif
+	}
+
+#ifdef ZX234290_PWR_FAUL_PROCESS
+	zx234290_regulator_error_irq_request(zx234290);
+#endif
+    //unsigned int gpio_num = irq_to_gpio(irq);//by yuxiang
+	//#define GPIO_PMU_INT ZX29_GPIO_50
+	/* GPIO reuse*/
+	zx29_gpio_config(pdata->irq_gpio_num, pdata->irq_gpio_func);
+#ifdef INT_LOW_LEVEL
+	zx29_gpio_set_inttype(pdata->irq_gpio_num, IRQ_TYPE_LEVEL_LOW);
+#else
+	zx29_gpio_set_inttype(pdata->irq_gpio_num, IRQ_TYPE_EDGE_FALLING);
+#endif
+	zx29_gpio_pd_pu_set(pdata->irq_gpio_num, 0);
+	//pcu_int_clear(PCU_EX0_INT); //by yuxiang
+	pcu_clr_irq_pending(irq);
+	//irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);//by yuxiang
+	//ret = request_threaded_irq(irq, irq_primary_handler, zx234290_irq, IRQF_ONESHOT,
+	//			   "zx234290", zx234290);
+	//µÈµ½pmuËùÓÐÄÚ²¿ÖжÏ×¢²áºó£¬ÔÙʹÄÜpmuÖжÏ
+	/* irq_set_status_flags(irq, IRQ_NOAUTOEN); */
+	ret = request_irq(irq, irq_primary_handler, IRQF_NO_THREAD,
+				   "zx234290", zx234290);
+	if (ret != 0)
+		dev_err(zx234290->dev, "Failed to request IRQ: %d\n", ret);
+	#ifndef CONFIG_ARCH_ZX297520V3_CAP	
+	irq_set_irq_wake(irq, 1);
+	#endif
+	kthread_run(zx234290_irq, zx234290, "irq/%d-%s", irq, "zx234290");
+	return ret;
+}
+
+int zx234290_irq_exit(struct zx234290 *zx234290)
+{
+	free_irq(zx234290->chip_irq, zx234290);
+
+	#ifdef ZX234290_WAKELOCK
+		wake_lock_destroy(&zx234290_wake_lock);
+	#endif
+
+	return 0;
+}