[PATCH] mfd: add irq support in 88pm860x

Haojian Zhuang haojian.zhuang at marvell.com
Fri Nov 13 10:19:02 EST 2009


88PM860x is a complex PMIC device. It contains touch, charger, sound, rtc,
backlight, led, and so on.

Host communicates to 88PM860x by I2C bus. Use thread irq to support this
usage case.

Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
 drivers/mfd/88pm860x-core.c  |  249 ++++++++++++++++++++++++++++++++++++++=
+---
 include/linux/mfd/88pm860x.h |   58 +++++-----
 2 files changed, 264 insertions(+), 43 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 0e6e80b..cc86089 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/i2c.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>

@@ -69,21 +70,228 @@ static struct mfd_cell pm8607_devs[] =3D {

 static struct mixed_88pm860x mixed_chip;

+#define CHECK_IRQ(irq)					\
+do {							\
+	if ((irq < 0) || (irq >=3D PM860X_NUM_IRQ))	\
+		return -EINVAL;				\
+} while (0)
+
+/* IRQs only occur on 88PM8607 */
+int pm860x_mask_irq(struct pm860x_chip *chip, int irq)
+{
+	int offset, data, ret;
+
+	CHECK_IRQ(irq);
+
+	offset =3D (irq >> 3) + PM8607_INT_MASK_1;
+	data =3D 1 << (irq % 8);
+	ret =3D pm860x_set_bits(chip->parent, DESC_8607, offset, data, 0);
+
+	return ret;
+}
+EXPORT_SYMBOL(pm860x_mask_irq);
+
+int pm860x_unmask_irq(struct pm860x_chip *chip, int irq)
+{
+	int offset, data, ret;
+
+	CHECK_IRQ(irq);
+
+	offset =3D (irq >> 3) + PM8607_INT_MASK_1;
+	data =3D 1 << (irq % 8);
+	ret =3D pm860x_set_bits(chip->parent, DESC_8607, offset, data, data);
+
+	return ret;
+}
+EXPORT_SYMBOL(pm860x_unmask_irq);
+
+#define INT_STATUS_NUM		(3)
+
+static irqreturn_t pm8607_irq_thread(int irq, void *data)
+{
+	DECLARE_BITMAP(irq_status, PM860X_NUM_IRQ);
+	struct pm860x_chip *chip =3D data;
+	unsigned char status_buf[INT_STATUS_NUM << 1];
+	unsigned long value;
+	int i, ret;
+
+	irq_status[0] =3D 0;
+
+	/* read out status register */
+	ret =3D pm860x_bulk_read(chip->parent, DESC_8607, PM8607_INT_STATUS1,
+				INT_STATUS_NUM << 1, status_buf);
+	if (ret < 0)
+		goto out;
+	if (chip->irq_mode) {
+		/* 0, clear by read. 1, clear by write */
+		ret =3D pm860x_bulk_write(chip->parent, DESC_8607,
+					PM8607_INT_STATUS1, INT_STATUS_NUM,
+					status_buf);
+		if (ret < 0)
+			goto out;
+	}
+
+	/* clear masked interrupt status */
+	for (i =3D 0, value =3D 0; i < INT_STATUS_NUM; i++) {
+		status_buf[i] &=3D status_buf[i + INT_STATUS_NUM];
+		irq_status[0] |=3D status_buf[i] << (i * 8);
+	}
+
+	while (!bitmap_empty(irq_status, PM860X_NUM_IRQ)) {
+		irq =3D find_first_bit(irq_status, PM860X_NUM_IRQ);
+		clear_bit(irq, irq_status);
+		dev_dbg(chip->dev, "Servicing IRQ #%d\n", irq);
+
+		mutex_lock(&chip->irq_lock);From
7afdf603753cf91e4753ce8f1c179fb55b68bf6d Mon Sep 17 00:00:00 2001
From: Haojian Zhuang <haojian.zhuang at marvell.com>
Date: Fri, 13 Nov 2009 10:19:02 -0500
Subject: [PATCH] mfd: add irq support in 88pm860x

88PM860x is a complex PMIC device. It contains touch, charger, sound, rtc,
backlight, led, and so on.

Host communicates to 88PM860x by I2C bus. Use thread irq to support this
usage case.

Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
 drivers/mfd/88pm860x-core.c  |  249 ++++++++++++++++++++++++++++++++++++++=
+---
 include/linux/mfd/88pm860x.h |   58 +++++-----
 2 files changed, 264 insertions(+), 43 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 0e6e80b..cc86089 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/i2c.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>

@@ -69,21 +70,228 @@ static struct mfd_cell pm8607_devs[] =3D {

 static struct mixed_88pm860x mixed_chip;

+#define CHECK_IRQ(irq)					\
+do {							\
+	if ((irq < 0) || (irq >=3D PM860X_NUM_IRQ))	\
+		return -EINVAL;				\
+} while (0)
+
+/* IRQs only occur on 88PM8607 */
+int pm860x_mask_irq(struct pm860x_chip *chip, int irq)
+{
+	int offset, data, ret;
+
+	CHECK_IRQ(irq);
+
+	offset =3D (irq >> 3) + PM8607_INT_MASK_1;
+	data =3D 1 << (irq % 8);
+	ret =3D pm860x_set_bits(chip->parent, DESC_8607, offset, data, 0);
+
+	return ret;
+}
+EXPORT_SYMBOL(pm860x_mask_irq);
+
+int pm860x_unmask_irq(struct pm860x_chip *chip, int irq)
+{
+	int offset, data, ret;
+
+	CHECK_IRQ(irq);
+
+	offset =3D (irq >> 3) + PM8607_INT_MASK_1;
+	data =3D 1 << (irq % 8);
+	ret =3D pm860x_set_bits(chip->parent, DESC_8607, offset, data, data);
+
+	return ret;
+}
+EXPORT_SYMBOL(pm860x_unmask_irq);
+
+#define INT_STATUS_NUM		(3)
+
+static irqreturn_t pm8607_irq_thread(int irq, void *data)
+{
+	DECLARE_BITMAP(irq_status, PM860X_NUM_IRQ);
+	struct pm860x_chip *chip =3D data;
+	unsigned char status_buf[INT_STATUS_NUM << 1];
+	unsigned long value;
+	int i, ret;
+
+	irq_status[0] =3D 0;
+
+	/* read out status register */
+	ret =3D pm860x_bulk_read(chip->parent, DESC_8607, PM8607_INT_STATUS1,
+				INT_STATUS_NUM << 1, status_buf);
+	if (ret < 0)
+		goto out;
+	if (chip->irq_mode) {
+		/* 0, clear by read. 1, clear by write */
+		ret =3D pm860x_bulk_write(chip->parent, DESC_8607,
+					PM8607_INT_STATUS1, INT_STATUS_NUM,
+					status_buf);
+		if (ret < 0)
+			goto out;
+	}
+
+	/* clear masked interrupt status */
+	for (i =3D 0, value =3D 0; i < INT_STATUS_NUM; i++) {
+		status_buf[i] &=3D status_buf[i + INT_STATUS_NUM];
+		irq_status[0] |=3D status_buf[i] << (i * 8);
+	}
+
+	while (!bitmap_empty(irq_status, PM860X_NUM_IRQ)) {
+		irq =3D find_first_bit(irq_status, PM860X_NUM_IRQ);
+		clear_bit(irq, irq_status);
+		dev_dbg(chip->dev, "Servicing IRQ #%d\n", irq);
+
+		mutex_lock(&chip->irq_lock);
+		if (chip->irq[irq].handler)
+			chip->irq[irq].handler(irq, chip->irq[irq].data);
+		else {
+			pm860x_mask_irq(chip, irq);
+			dev_err(chip->dev, "Nobody cares IRQ %d. "
+				"Now mask it.\n", irq);
+			for (i =3D 0; i < (INT_STATUS_NUM << 1); i++) {
+				dev_err(chip->dev, "status[%d]:%x\n", i,
+					status_buf[i]);
+			}
+		}
+		mutex_unlock(&chip->irq_lock);
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+int pm860x_request_irq(struct pm860x_chip *chip, int irq,
+		       irq_handler_t handler, void *data)
+{
+	CHECK_IRQ(irq);
+	if (!handler)
+		return -EINVAL;
+
+	mutex_lock(&chip->irq_lock);
+	chip->irq[irq].handler =3D handler;
+	chip->irq[irq].data =3D data;
+	mutex_unlock(&chip->irq_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pm860x_request_irq);
+
+int pm860x_free_irq(struct pm860x_chip *chip, int irq)
+{
+	CHECK_IRQ(irq);
+
+	mutex_lock(&chip->irq_lock);
+	chip->irq[irq].handler =3D NULL;
+	chip->irq[irq].data =3D NULL;
+	mutex_unlock(&chip->irq_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pm860x_free_irq);
+
+static int __devinit __88pm8607_irq_init(struct pm860x_chip *chip,
+					 struct pm860x_plat_data *pdata)
+{
+	unsigned char status_buf[INT_STATUS_NUM];
+	int irq, data, mask, ret =3D -EINVAL;
+
+	mutex_init(&chip->irq_lock);
+
+	mask =3D PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
+		| PM8607_B0_MISC1_INT_MASK;
+	data =3D PM8607_B0_MISC1_INT_CLEAR;
+	chip->irq_mode =3D 1;
+	switch (chip->chip_id) {
+	case PM8607_CHIP_A0:
+	case PM8607_CHIP_A1:
+		ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+				PM8607_A1_MISC1, mask, data);
+		break;
+	case PM8607_CHIP_B0:
+	default:
+		if (pdata) {
+			/*
+			 * irq_mode defines the way of clearing interrupt. If
+			 * it's 1, clear IRQ by write. Otherwise, clear it by
+			 * read.
+			 * This control bit is valid from 88PM8607 B0 steping.
+			 */
+			if (!pdata->irq_mode) {
+				data =3D 0;
+				chip->irq_mode =3D 0;
+			}
+		}
+		ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+				PM8607_B0_MISC1, mask, data);
+		break;
+	}
+	if (ret < 0)
+		goto out;
+
+	/* mask all IRQs */
+	memset(status_buf, 0, INT_STATUS_NUM);
+	ret =3D pm860x_bulk_write(chip->parent, DESC_8607, PM8607_INT_MASK_1,
+				INT_STATUS_NUM, status_buf);
+	if (ret < 0)
+		goto out;
+
+	if (chip->irq_mode) {
+		/* clear interrupt status by write */
+		memset(status_buf, 0xFF, INT_STATUS_NUM);
+		ret =3D pm860x_bulk_write(chip->parent, DESC_8607,
+					PM8607_INT_STATUS1,
+					INT_STATUS_NUM, status_buf);
+	} else {
+		/* clear interrupt status by read */
+		ret =3D pm860x_bulk_read(chip->parent, DESC_8607,
+					PM8607_INT_STATUS1,
+					INT_STATUS_NUM, status_buf);
+	}
+	if (ret < 0)
+		goto out;
+
+	memset(chip->irq, 0, sizeof(struct pm860x_irq) * PM860X_NUM_IRQ);
+
+	if (chip->client =3D=3D NULL)
+		goto out;
+
+	irq =3D chip->client->irq;
+	ret =3D request_threaded_irq(irq, NULL, pm8607_irq_thread,
+				IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+				"88pm8607", chip);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to request IRQ #%d.\n", irq);
+		goto out;
+	}
+	chip->chip_irq =3D ret;
+	return 0;
+out:
+	return ret;
+}
+
+static void __devexit __88pm860x_irq_exit(struct pm860x_chip *chip)
+{
+	if (chip->chip_irq >=3D 0)
+		free_irq(chip->chip_irq, chip);
+}
+
 static int __devinit __88pm8606_init(struct pm860x_chip *chip, void *pdata=
)
 {
 	chip->parent =3D &mixed_chip;
 	mixed_chip.pm8606 =3D chip;
+	chip->chip_irq =3D -EINVAL;

 	return 0;
 }

 static int __devinit __88pm8607_init(struct pm860x_chip *chip,
-				     struct pm8607_plat_data *pdata)
+				     struct pm860x_plat_data *pdata)
 {
-	int ret =3D 0;
+	int data =3D 0, ret =3D 0;

 	chip->parent =3D &mixed_chip;
 	mixed_chip.pm8607 =3D chip;
+	chip->chip_irq =3D -EINVAL;

 	ret =3D pm860x_reg_read(chip->parent, DESC_8607, PM8607_CHIP_ID);
 	if (ret < 0) {
@@ -108,20 +316,30 @@ static int __devinit __88pm8607_init(struct
pm860x_chip *chip,
 	if (ret & PM8607_BUCK3_DOUBLE)
 		chip->parent->buck3_double =3D 1;

-	ret =3D pm860x_reg_read(chip->parent, DESC_8607, PM8607_MISC1);
-	if (ret < 0) {
-		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
-		goto out;
+	if (pdata && (pdata->i2c_port =3D=3D PI2C_PORT)) {
+		switch (chip->chip_id) {
+		case PM8607_CHIP_A0:
+		case PM8607_CHIP_A1:
+			data =3D PM8607_A1_MISC1_PI2C;
+			ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+					PM8607_A1_MISC1, data, data);
+			break;
+		case PM8607_CHIP_B0:
+		default:
+			data =3D PM8607_B0_MISC1_PI2C;
+			ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+					PM8607_B0_MISC1, data, data);
+			break;
+		}
+		if (ret < 0) {
+			dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
+			goto out;
+		}
 	}
-	if (pdata && (pdata->i2c_port =3D=3D PI2C_PORT))
-		ret |=3D PM8607_MISC1_PI2C;
-	else
-		ret &=3D ~PM8607_MISC1_PI2C;
-	ret =3D pm860x_reg_write(chip->parent, DESC_8607, PM8607_MISC1, ret);
-	if (ret < 0) {
-		dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
+
+	ret =3D __88pm8607_irq_init(chip, pdata);
+	if (ret < 0)
 		goto out;
-	}
 out:
 	return ret;
 }
@@ -136,7 +354,7 @@ int __devinit pm860x_device_init(struct
pm860x_chip *chip, void *pdata)
 		mutex_init(&mixed_chip.io_lock);

 	if (!strcmp(chip->id.name, "88PM8607")) {
-		ret =3D __88pm8607_init(chip, (struct pm8607_plat_data *)pdata);
+		ret =3D __88pm8607_init(chip, (struct pm860x_plat_data *)pdata);
 		if (ret < 0)
 			goto out;

@@ -160,6 +378,7 @@ out:

 void __devexit pm8607_device_exit(struct pm860x_chip *chip)
 {
+	__88pm860x_irq_exit(chip);
 	mfd_remove_devices(chip->dev);
 }

diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index fd8e8ad..99a5a7e 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -12,6 +12,8 @@
 #ifndef __LINUX_MFD_88PM860X_H
 #define __LINUX_MFD_88PM860X_H

+#include <linux/interrupt.h>
+
 enum {
 	DESC_INVAL =3D 0,
 	DESC_8606,
@@ -109,33 +111,10 @@ enum {

 /* Misc Registers */
 #define PM8607_CHIP_ID			(0x00)
+#define PM8607_B0_MISC1			(0x0C)
 #define PM8607_LDO1			(0x10)
 #define PM8607_DVC3			(0x26)
-#define PM8607_MISC1			(0x40)
-
-/* bit definitions for PM8607 events */
-#define PM8607_EVENT_ONKEY		(1 << 0)
-#define PM8607_EVENT_EXTON		(1 << 1)
-#define PM8607_EVENT_CHG		(1 << 2)
-#define PM8607_EVENT_BAT		(1 << 3)
-#define PM8607_EVENT_RTC		(1 << 4)
-#define PM8607_EVENT_CC			(1 << 5)
-#define PM8607_EVENT_VBAT		(1 << 8)
-#define PM8607_EVENT_VCHG		(1 << 9)
-#define PM8607_EVENT_VSYS		(1 << 10)
-#define PM8607_EVENT_TINT		(1 << 11)
-#define PM8607_EVENT_GPADC0		(1 << 12)
-#define PM8607_EVENT_GPADC1		(1 << 13)
-#define PM8607_EVENT_GPADC2		(1 << 14)
-#define PM8607_EVENT_GPADC3		(1 << 15)
-#define PM8607_EVENT_AUDIO_SHORT	(1 << 16)
-#define PM8607_EVENT_PEN		(1 << 17)
-#define PM8607_EVENT_HEADSET		(1 << 18)
-#define PM8607_EVENT_HOOK		(1 << 19)
-#define PM8607_EVENT_MICIN		(1 << 20)
-#define PM8607_EVENT_CHG_TIMEOUT	(1 << 21)
-#define PM8607_EVENT_CHG_DONE		(1 << 22)
-#define PM8607_EVENT_CHG_FAULT		(1 << 23)
+#define PM8607_A1_MISC1			(0x40)

 /* bit definitions of Status Query Interface */
 #define PM8607_STATUS_CC		(1 << 3)
@@ -154,7 +133,12 @@ enum {
 #define PM8607_BUCK3_DOUBLE		(1 << 6)

 /* bit definitions of Misc1 */
-#define PM8607_MISC1_PI2C		(1 << 0)
+#define PM8607_A1_MISC1_PI2C		(1 << 0)
+#define PM8607_B0_MISC1_INV_INT		(1 << 0)
+#define PM8607_B0_MISC1_INT_CLEAR	(1 << 1)
+#define PM8607_B0_MISC1_INT_MASK	(1 << 2)
+#define PM8607_B0_MISC1_PI2C		(1 << 3)
+#define PM8607_B0_MISC1_RESET		(1 << 6)

 /* Interrupt Number in 88PM8607 */
 enum {
@@ -199,14 +183,25 @@ struct mixed_88pm860x {
 	int			flags;
 };

+#define PM860X_NUM_IRQ		24
+
+struct pm860x_irq {
+	irq_handler_t		handler;
+	void			*data;
+};
+
 struct pm860x_chip {
 	struct device		*dev;
-	struct mutex		io_lock;
 	struct i2c_client	*client;
 	struct i2c_device_id	id;
 	struct mixed_88pm860x	*parent;
+	struct mutex		irq_lock;
+	int			chip_irq;
 	unsigned char		chip_id;

+	struct pm860x_irq	irq[PM860X_NUM_IRQ];
+	int			irq_mode;
+
 	int (*read)(struct pm860x_chip *chip, int reg, int bytes, void *dest);
 	int (*write)(struct pm860x_chip *chip, int reg, int bytes, void *src);
 };
@@ -218,8 +213,9 @@ enum {
 	PI2C_PORT,
 };

-struct pm8607_plat_data {
+struct pm860x_plat_data {
 	int	i2c_port;	/* Controlled by GI2C or PI2C */
+	int	irq_mode;	/* Clear interrupt by read/write (1/0) */
 	struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
 };

@@ -232,6 +228,12 @@ extern int pm860x_bulk_write(struct
mixed_88pm860x *, int, int, int,
 extern int pm860x_set_bits(struct mixed_88pm860x *, int, int, unsigned cha=
r,
 			   unsigned char);

+extern int pm860x_mask_irq(struct pm860x_chip *, int);
+extern int pm860x_unmask_irq(struct pm860x_chip *, int);
+extern int pm860x_request_irq(struct pm860x_chip *, int,
+			      irq_handler_t handler, void *);
+extern int pm860x_free_irq(struct pm860x_chip *, int);
+
 extern int pm860x_device_init(struct pm860x_chip *chip, void *pdata);
 extern void pm860x_device_exit(struct pm860x_chip *chip);

--=20
1.5.6.5

+		if (chip->irq[irq].handler)
+			chip->irq[irq].handler(irq, chip->irq[irq].data);
+		else {
+			pm860x_mask_irq(chip, irq);
+			dev_err(chip->dev, "Nobody cares IRQ %d. "
+				"Now mask it.\n", irq);
+			for (i =3D 0; i < (INT_STATUS_NUM << 1); i++) {
+				dev_err(chip->dev, "status[%d]:%x\n", i,
+					status_buf[i]);
+			}
+		}
+		mutex_unlock(&chip->irq_lock);
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+int pm860x_request_irq(struct pm860x_chip *chip, int irq,
+		       irq_handler_t handler, void *data)
+{
+	CHECK_IRQ(irq);
+	if (!handler)
+		return -EINVAL;
+
+	mutex_lock(&chip->irq_lock);
+	chip->irq[irq].handler =3D handler;
+	chip->irq[irq].data =3D data;
+	mutex_unlock(&chip->irq_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pm860x_request_irq);
+
+int pm860x_free_irq(struct pm860x_chip *chip, int irq)
+{
+	CHECK_IRQ(irq);
+
+	mutex_lock(&chip->irq_lock);
+	chip->irq[irq].handler =3D NULL;
+	chip->irq[irq].data =3D NULL;
+	mutex_unlock(&chip->irq_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pm860x_free_irq);
+
+static int __devinit __88pm8607_irq_init(struct pm860x_chip *chip,
+					 struct pm860x_plat_data *pdata)
+{
+	unsigned char status_buf[INT_STATUS_NUM];
+	int irq, data, mask, ret =3D -EINVAL;
+
+	mutex_init(&chip->irq_lock);
+
+	mask =3D PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
+		| PM8607_B0_MISC1_INT_MASK;
+	data =3D PM8607_B0_MISC1_INT_CLEAR;
+	chip->irq_mode =3D 1;
+	switch (chip->chip_id) {
+	case PM8607_CHIP_A0:
+	case PM8607_CHIP_A1:
+		ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+				PM8607_A1_MISC1, mask, data);
+		break;
+	case PM8607_CHIP_B0:
+	default:
+		if (pdata) {
+			/*
+			 * irq_mode defines the way of clearing interrupt. If
+			 * it's 1, clear IRQ by write. Otherwise, clear it by
+			 * read.
+			 * This control bit is valid from 88PM8607 B0 steping.
+			 */
+			if (!pdata->irq_mode) {
+				data =3D 0;
+				chip->irq_mode =3D 0;
+			}
+		}
+		ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+				PM8607_B0_MISC1, mask, data);
+		break;
+	}
+	if (ret < 0)
+		goto out;
+
+	/* mask all IRQs */
+	memset(status_buf, 0, INT_STATUS_NUM);
+	ret =3D pm860x_bulk_write(chip->parent, DESC_8607, PM8607_INT_MASK_1,
+				INT_STATUS_NUM, status_buf);
+	if (ret < 0)
+		goto out;
+
+	if (chip->irq_mode) {
+		/* clear interrupt status by write */
+		memset(status_buf, 0xFF, INT_STATUS_NUM);
+		ret =3D pm860x_bulk_write(chip->parent, DESC_8607,
+					PM8607_INT_STATUS1,
+					INT_STATUS_NUM, status_buf);
+	} else {
+		/* clear interrupt status by read */
+		ret =3D pm860x_bulk_read(chip->parent, DESC_8607,
+					PM8607_INT_STATUS1,
+					INT_STATUS_NUM, status_buf);
+	}
+	if (ret < 0)
+		goto out;
+
+	memset(chip->irq, 0, sizeof(struct pm860x_irq) * PM860X_NUM_IRQ);
+
+	if (chip->client =3D=3D NULL)
+		goto out;
+
+	irq =3D chip->client->irq;
+	ret =3D request_threaded_irq(irq, NULL, pm8607_irq_thread,
+				IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+				"88pm8607", chip);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to request IRQ #%d.\n", irq);
+		goto out;
+	}
+	chip->chip_irq =3D ret;
+	return 0;
+out:
+	return ret;
+}
+
+static void __devexit __88pm860x_irq_exit(struct pm860x_chip *chip)
+{
+	if (chip->chip_irq >=3D 0)
+		free_irq(chip->chip_irq, chip);
+}
+
 static int __devinit __88pm8606_init(struct pm860x_chip *chip, void *pdata=
)
 {
 	chip->parent =3D &mixed_chip;
 	mixed_chip.pm8606 =3D chip;
+	chip->chip_irq =3D -EINVAL;

 	return 0;
 }

 static int __devinit __88pm8607_init(struct pm860x_chip *chip,
-				     struct pm8607_plat_data *pdata)
+				     struct pm860x_plat_data *pdata)
 {
-	int ret =3D 0;
+	int data =3D 0, ret =3D 0;

 	chip->parent =3D &mixed_chip;
 	mixed_chip.pm8607 =3D chip;
+	chip->chip_irq =3D -EINVAL;

 	ret =3D pm860x_reg_read(chip->parent, DESC_8607, PM8607_CHIP_ID);
 	if (ret < 0) {
@@ -108,20 +316,30 @@ static int __devinit __88pm8607_init(struct
pm860x_chip *chip,
 	if (ret & PM8607_BUCK3_DOUBLE)
 		chip->parent->buck3_double =3D 1;

-	ret =3D pm860x_reg_read(chip->parent, DESC_8607, PM8607_MISC1);
-	if (ret < 0) {
-		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
-		goto out;
+	if (pdata && (pdata->i2c_port =3D=3D PI2C_PORT)) {
+		switch (chip->chip_id) {
+		case PM8607_CHIP_A0:
+		case PM8607_CHIP_A1:
+			data =3D PM8607_A1_MISC1_PI2C;
+			ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+					PM8607_A1_MISC1, data, data);
+			break;
+		case PM8607_CHIP_B0:
+		default:
+			data =3D PM8607_B0_MISC1_PI2C;
+			ret =3D pm860x_set_bits(chip->parent, DESC_8607,
+					PM8607_B0_MISC1, data, data);
+			break;
+		}
+		if (ret < 0) {
+			dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);
+			goto out;
+		}
 	}
-	if (pdata && (pdata->i2c_port =3D=3D PI2C_PORT))
-		ret |=3D PM8607_MISC1_PI2C;
-	else
-		ret &=3D ~PM8607_MISC1_PI2C;
-	ret =3D pm860x_reg_write(chip->parent, DESC_8607, PM8607_MISC1, ret);
-	if (ret < 0) {
-		dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
+
+	ret =3D __88pm8607_irq_init(chip, pdata);
+	if (ret < 0)
 		goto out;
-	}
 out:
 	return ret;
 }
@@ -136,7 +354,7 @@ int __devinit pm860x_device_init(struct
pm860x_chip *chip, void *pdata)
 		mutex_init(&mixed_chip.io_lock);

 	if (!strcmp(chip->id.name, "88PM8607")) {
-		ret =3D __88pm8607_init(chip, (struct pm8607_plat_data *)pdata);
+		ret =3D __88pm8607_init(chip, (struct pm860x_plat_data *)pdata);
 		if (ret < 0)
 			goto out;

@@ -160,6 +378,7 @@ out:

 void __devexit pm8607_device_exit(struct pm860x_chip *chip)
 {
+	__88pm860x_irq_exit(chip);
 	mfd_remove_devices(chip->dev);
 }

diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index fd8e8ad..99a5a7e 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -12,6 +12,8 @@
 #ifndef __LINUX_MFD_88PM860X_H
 #define __LINUX_MFD_88PM860X_H

+#include <linux/interrupt.h>
+
 enum {
 	DESC_INVAL =3D 0,
 	DESC_8606,
@@ -109,33 +111,10 @@ enum {

 /* Misc Registers */
 #define PM8607_CHIP_ID			(0x00)
+#define PM8607_B0_MISC1			(0x0C)
 #define PM8607_LDO1			(0x10)
 #define PM8607_DVC3			(0x26)
-#define PM8607_MISC1			(0x40)
-
-/* bit definitions for PM8607 events */
-#define PM8607_EVENT_ONKEY		(1 << 0)
-#define PM8607_EVENT_EXTON		(1 << 1)
-#define PM8607_EVENT_CHG		(1 << 2)
-#define PM8607_EVENT_BAT		(1 << 3)
-#define PM8607_EVENT_RTC		(1 << 4)
-#define PM8607_EVENT_CC			(1 << 5)
-#define PM8607_EVENT_VBAT		(1 << 8)
-#define PM8607_EVENT_VCHG		(1 << 9)
-#define PM8607_EVENT_VSYS		(1 << 10)
-#define PM8607_EVENT_TINT		(1 << 11)
-#define PM8607_EVENT_GPADC0		(1 << 12)
-#define PM8607_EVENT_GPADC1		(1 << 13)
-#define PM8607_EVENT_GPADC2		(1 << 14)
-#define PM8607_EVENT_GPADC3		(1 << 15)
-#define PM8607_EVENT_AUDIO_SHORT	(1 << 16)
-#define PM8607_EVENT_PEN		(1 << 17)
-#define PM8607_EVENT_HEADSET		(1 << 18)
-#define PM8607_EVENT_HOOK		(1 << 19)
-#define PM8607_EVENT_MICIN		(1 << 20)
-#define PM8607_EVENT_CHG_TIMEOUT	(1 << 21)
-#define PM8607_EVENT_CHG_DONE		(1 << 22)
-#define PM8607_EVENT_CHG_FAULT		(1 << 23)
+#define PM8607_A1_MISC1			(0x40)

 /* bit definitions of Status Query Interface */
 #define PM8607_STATUS_CC		(1 << 3)
@@ -154,7 +133,12 @@ enum {
 #define PM8607_BUCK3_DOUBLE		(1 << 6)

 /* bit definitions of Misc1 */
-#define PM8607_MISC1_PI2C		(1 << 0)
+#define PM8607_A1_MISC1_PI2C		(1 << 0)
+#define PM8607_B0_MISC1_INV_INT		(1 << 0)
+#define PM8607_B0_MISC1_INT_CLEAR	(1 << 1)
+#define PM8607_B0_MISC1_INT_MASK	(1 << 2)
+#define PM8607_B0_MISC1_PI2C		(1 << 3)
+#define PM8607_B0_MISC1_RESET		(1 << 6)

 /* Interrupt Number in 88PM8607 */
 enum {
@@ -199,14 +183,25 @@ struct mixed_88pm860x {
 	int			flags;
 };

+#define PM860X_NUM_IRQ		24
+
+struct pm860x_irq {
+	irq_handler_t		handler;
+	void			*data;
+};
+
 struct pm860x_chip {
 	struct device		*dev;
-	struct mutex		io_lock;
 	struct i2c_client	*client;
 	struct i2c_device_id	id;
 	struct mixed_88pm860x	*parent;
+	struct mutex		irq_lock;
+	int			chip_irq;
 	unsigned char		chip_id;

+	struct pm860x_irq	irq[PM860X_NUM_IRQ];
+	int			irq_mode;
+
 	int (*read)(struct pm860x_chip *chip, int reg, int bytes, void *dest);
 	int (*write)(struct pm860x_chip *chip, int reg, int bytes, void *src);
 };
@@ -218,8 +213,9 @@ enum {
 	PI2C_PORT,
 };

-struct pm8607_plat_data {
+struct pm860x_plat_data {
 	int	i2c_port;	/* Controlled by GI2C or PI2C */
+	int	irq_mode;	/* Clear interrupt by read/write (1/0) */
 	struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
 };

@@ -232,6 +228,12 @@ extern int pm860x_bulk_write(struct
mixed_88pm860x *, int, int, int,
 extern int pm860x_set_bits(struct mixed_88pm860x *, int, int, unsigned cha=
r,
 			   unsigned char);

+extern int pm860x_mask_irq(struct pm860x_chip *, int);
+extern int pm860x_unmask_irq(struct pm860x_chip *, int);
+extern int pm860x_request_irq(struct pm860x_chip *, int,
+			      irq_handler_t handler, void *);
+extern int pm860x_free_irq(struct pm860x_chip *, int);
+
 extern int pm860x_device_init(struct pm860x_chip *chip, void *pdata);
 extern void pm860x_device_exit(struct pm860x_chip *chip);

--=20
1.5.6.5

--00151773da30083edf04788b4bfe
Content-Type: text/x-patch; charset=US-ASCII; 
	name="0005-mfd-add-irq-support-in-88pm860x.patch"
Content-Disposition: attachment; 
	filename="0005-mfd-add-irq-support-in-88pm860x.patch"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_g24r5qk70

RnJvbSA3YWZkZjYwMzc1M2NmOTFlNDc1M2NlOGYxYzE3OWZiNTViNjhiZjZkIE1vbiBTZXAgMTcg
MDA6MDA6MDAgMjAwMQpGcm9tOiBIYW9qaWFuIFpodWFuZyA8aGFvamlhbi56aHVhbmdAbWFydmVs
bC5jb20+CkRhdGU6IEZyaSwgMTMgTm92IDIwMDkgMTA6MTk6MDIgLTA1MDAKU3ViamVjdDogW1BB
VENIXSBtZmQ6IGFkZCBpcnEgc3VwcG9ydCBpbiA4OHBtODYweAoKODhQTTg2MHggaXMgYSBjb21w
bGV4IFBNSUMgZGV2aWNlLiBJdCBjb250YWlucyB0b3VjaCwgY2hhcmdlciwgc291bmQsIHJ0YywK
YmFja2xpZ2h0LCBsZWQsIGFuZCBzbyBvbi4KCkhvc3QgY29tbXVuaWNhdGVzIHRvIDg4UE04NjB4
IGJ5IEkyQyBidXMuIFVzZSB0aHJlYWQgaXJxIHRvIHN1cHBvcnQgdGhpcwp1c2FnZSBjYXNlLgoK
U2lnbmVkLW9mZi1ieTogSGFvamlhbiBaaHVhbmcgPGhhb2ppYW4uemh1YW5nQG1hcnZlbGwuY29t
PgotLS0KIGRyaXZlcnMvbWZkLzg4cG04NjB4LWNvcmUuYyAgfCAgMjQ5ICsrKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKy0tLQogaW5jbHVkZS9saW51eC9tZmQvODhwbTg2MHgu
aCB8ICAgNTggKysrKystLS0tLQogMiBmaWxlcyBjaGFuZ2VkLCAyNjQgaW5zZXJ0aW9ucygrKSwg
NDMgZGVsZXRpb25zKC0pCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9tZmQvODhwbTg2MHgtY29yZS5j
IGIvZHJpdmVycy9tZmQvODhwbTg2MHgtY29yZS5jCmluZGV4IDBlNmU4MGIuLmNjODYwODkgMTAw
NjQ0Ci0tLSBhL2RyaXZlcnMvbWZkLzg4cG04NjB4LWNvcmUuYworKysgYi9kcml2ZXJzL21mZC84
OHBtODYweC1jb3JlLmMKQEAgLTEzLDYgKzEzLDcgQEAKICNpbmNsdWRlIDxsaW51eC9tb2R1bGUu
aD4KICNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4KICNpbmNsdWRlIDxsaW51eC9wbGF0Zm9y
bV9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9pMmMuaD4KICNpbmNsdWRlIDxsaW51eC9tZmQv
Y29yZS5oPgogI2luY2x1ZGUgPGxpbnV4L21mZC84OHBtODYweC5oPgogCkBAIC02OSwyMSArNzAs
MjI4IEBAIHN0YXRpYyBzdHJ1Y3QgbWZkX2NlbGwgcG04NjA3X2RldnNbXSA9IHsKIAogc3RhdGlj
IHN0cnVjdCBtaXhlZF84OHBtODYweCBtaXhlZF9jaGlwOwogCisjZGVmaW5lIENIRUNLX0lSUShp
cnEpCQkJCQlcCitkbyB7CQkJCQkJCVwKKwlpZiAoKGlycSA8IDApIHx8IChpcnEgPj0gUE04NjBY
X05VTV9JUlEpKQlcCisJCXJldHVybiAtRUlOVkFMOwkJCQlcCit9IHdoaWxlICgwKQorCisvKiBJ
UlFzIG9ubHkgb2NjdXIgb24gODhQTTg2MDcgKi8KK2ludCBwbTg2MHhfbWFza19pcnEoc3RydWN0
IHBtODYweF9jaGlwICpjaGlwLCBpbnQgaXJxKQoreworCWludCBvZmZzZXQsIGRhdGEsIHJldDsK
KworCUNIRUNLX0lSUShpcnEpOworCisJb2Zmc2V0ID0gKGlycSA+PiAzKSArIFBNODYwN19JTlRf
TUFTS18xOworCWRhdGEgPSAxIDw8IChpcnEgJSA4KTsKKwlyZXQgPSBwbTg2MHhfc2V0X2JpdHMo
Y2hpcC0+cGFyZW50LCBERVNDXzg2MDcsIG9mZnNldCwgZGF0YSwgMCk7CisKKwlyZXR1cm4gcmV0
OworfQorRVhQT1JUX1NZTUJPTChwbTg2MHhfbWFza19pcnEpOworCitpbnQgcG04NjB4X3VubWFz
a19pcnEoc3RydWN0IHBtODYweF9jaGlwICpjaGlwLCBpbnQgaXJxKQoreworCWludCBvZmZzZXQs
IGRhdGEsIHJldDsKKworCUNIRUNLX0lSUShpcnEpOworCisJb2Zmc2V0ID0gKGlycSA+PiAzKSAr
IFBNODYwN19JTlRfTUFTS18xOworCWRhdGEgPSAxIDw8IChpcnEgJSA4KTsKKwlyZXQgPSBwbTg2
MHhfc2V0X2JpdHMoY2hpcC0+cGFyZW50LCBERVNDXzg2MDcsIG9mZnNldCwgZGF0YSwgZGF0YSk7
CisKKwlyZXR1cm4gcmV0OworfQorRVhQT1JUX1NZTUJPTChwbTg2MHhfdW5tYXNrX2lycSk7CisK
KyNkZWZpbmUgSU5UX1NUQVRVU19OVU0JCSgzKQorCitzdGF0aWMgaXJxcmV0dXJuX3QgcG04NjA3
X2lycV90aHJlYWQoaW50IGlycSwgdm9pZCAqZGF0YSkKK3sKKwlERUNMQVJFX0JJVE1BUChpcnFf
c3RhdHVzLCBQTTg2MFhfTlVNX0lSUSk7CisJc3RydWN0IHBtODYweF9jaGlwICpjaGlwID0gZGF0
YTsKKwl1bnNpZ25lZCBjaGFyIHN0YXR1c19idWZbSU5UX1NUQVRVU19OVU0gPDwgMV07CisJdW5z
aWduZWQgbG9uZyB2YWx1ZTsKKwlpbnQgaSwgcmV0OworCisJaXJxX3N0YXR1c1swXSA9IDA7CisK
KwkvKiByZWFkIG91dCBzdGF0dXMgcmVnaXN0ZXIgKi8KKwlyZXQgPSBwbTg2MHhfYnVsa19yZWFk
KGNoaXAtPnBhcmVudCwgREVTQ184NjA3LCBQTTg2MDdfSU5UX1NUQVRVUzEsCisJCQkJSU5UX1NU
QVRVU19OVU0gPDwgMSwgc3RhdHVzX2J1Zik7CisJaWYgKHJldCA8IDApCisJCWdvdG8gb3V0Owor
CWlmIChjaGlwLT5pcnFfbW9kZSkgeworCQkvKiAwLCBjbGVhciBieSByZWFkLiAxLCBjbGVhciBi
eSB3cml0ZSAqLworCQlyZXQgPSBwbTg2MHhfYnVsa193cml0ZShjaGlwLT5wYXJlbnQsIERFU0Nf
ODYwNywKKwkJCQkJUE04NjA3X0lOVF9TVEFUVVMxLCBJTlRfU1RBVFVTX05VTSwKKwkJCQkJc3Rh
dHVzX2J1Zik7CisJCWlmIChyZXQgPCAwKQorCQkJZ290byBvdXQ7CisJfQorCisJLyogY2xlYXIg
bWFza2VkIGludGVycnVwdCBzdGF0dXMgKi8KKwlmb3IgKGkgPSAwLCB2YWx1ZSA9IDA7IGkgPCBJ
TlRfU1RBVFVTX05VTTsgaSsrKSB7CisJCXN0YXR1c19idWZbaV0gJj0gc3RhdHVzX2J1ZltpICsg
SU5UX1NUQVRVU19OVU1dOworCQlpcnFfc3RhdHVzWzBdIHw9IHN0YXR1c19idWZbaV0gPDwgKGkg
KiA4KTsKKwl9CisKKwl3aGlsZSAoIWJpdG1hcF9lbXB0eShpcnFfc3RhdHVzLCBQTTg2MFhfTlVN
X0lSUSkpIHsKKwkJaXJxID0gZmluZF9maXJzdF9iaXQoaXJxX3N0YXR1cywgUE04NjBYX05VTV9J
UlEpOworCQljbGVhcl9iaXQoaXJxLCBpcnFfc3RhdHVzKTsKKwkJZGV2X2RiZyhjaGlwLT5kZXYs
ICJTZXJ2aWNpbmcgSVJRICMlZFxuIiwgaXJxKTsKKworCQltdXRleF9sb2NrKCZjaGlwLT5pcnFf
bG9jayk7CisJCWlmIChjaGlwLT5pcnFbaXJxXS5oYW5kbGVyKQorCQkJY2hpcC0+aXJxW2lycV0u
aGFuZGxlcihpcnEsIGNoaXAtPmlycVtpcnFdLmRhdGEpOworCQllbHNlIHsKKwkJCXBtODYweF9t
YXNrX2lycShjaGlwLCBpcnEpOworCQkJZGV2X2VycihjaGlwLT5kZXYsICJOb2JvZHkgY2FyZXMg
SVJRICVkLiAiCisJCQkJIk5vdyBtYXNrIGl0LlxuIiwgaXJxKTsKKwkJCWZvciAoaSA9IDA7IGkg
PCAoSU5UX1NUQVRVU19OVU0gPDwgMSk7IGkrKykgeworCQkJCWRldl9lcnIoY2hpcC0+ZGV2LCAi
c3RhdHVzWyVkXToleFxuIiwgaSwKKwkJCQkJc3RhdHVzX2J1ZltpXSk7CisJCQl9CisJCX0KKwkJ
bXV0ZXhfdW5sb2NrKCZjaGlwLT5pcnFfbG9jayk7CisJfQorb3V0OgorCXJldHVybiBJUlFfSEFO
RExFRDsKK30KKworaW50IHBtODYweF9yZXF1ZXN0X2lycShzdHJ1Y3QgcG04NjB4X2NoaXAgKmNo
aXAsIGludCBpcnEsCisJCSAgICAgICBpcnFfaGFuZGxlcl90IGhhbmRsZXIsIHZvaWQgKmRhdGEp
Cit7CisJQ0hFQ0tfSVJRKGlycSk7CisJaWYgKCFoYW5kbGVyKQorCQlyZXR1cm4gLUVJTlZBTDsK
KworCW11dGV4X2xvY2soJmNoaXAtPmlycV9sb2NrKTsKKwljaGlwLT5pcnFbaXJxXS5oYW5kbGVy
ID0gaGFuZGxlcjsKKwljaGlwLT5pcnFbaXJxXS5kYXRhID0gZGF0YTsKKwltdXRleF91bmxvY2so
JmNoaXAtPmlycV9sb2NrKTsKKworCXJldHVybiAwOworfQorRVhQT1JUX1NZTUJPTChwbTg2MHhf
cmVxdWVzdF9pcnEpOworCitpbnQgcG04NjB4X2ZyZWVfaXJxKHN0cnVjdCBwbTg2MHhfY2hpcCAq
Y2hpcCwgaW50IGlycSkKK3sKKwlDSEVDS19JUlEoaXJxKTsKKworCW11dGV4X2xvY2soJmNoaXAt
PmlycV9sb2NrKTsKKwljaGlwLT5pcnFbaXJxXS5oYW5kbGVyID0gTlVMTDsKKwljaGlwLT5pcnFb
aXJxXS5kYXRhID0gTlVMTDsKKwltdXRleF91bmxvY2soJmNoaXAtPmlycV9sb2NrKTsKKworCXJl
dHVybiAwOworfQorRVhQT1JUX1NZTUJPTChwbTg2MHhfZnJlZV9pcnEpOworCitzdGF0aWMgaW50
IF9fZGV2aW5pdCBfXzg4cG04NjA3X2lycV9pbml0KHN0cnVjdCBwbTg2MHhfY2hpcCAqY2hpcCwK
KwkJCQkJIHN0cnVjdCBwbTg2MHhfcGxhdF9kYXRhICpwZGF0YSkKK3sKKwl1bnNpZ25lZCBjaGFy
IHN0YXR1c19idWZbSU5UX1NUQVRVU19OVU1dOworCWludCBpcnEsIGRhdGEsIG1hc2ssIHJldCA9
IC1FSU5WQUw7CisKKwltdXRleF9pbml0KCZjaGlwLT5pcnFfbG9jayk7CisKKwltYXNrID0gUE04
NjA3X0IwX01JU0MxX0lOVl9JTlQgfCBQTTg2MDdfQjBfTUlTQzFfSU5UX0NMRUFSCisJCXwgUE04
NjA3X0IwX01JU0MxX0lOVF9NQVNLOworCWRhdGEgPSBQTTg2MDdfQjBfTUlTQzFfSU5UX0NMRUFS
OworCWNoaXAtPmlycV9tb2RlID0gMTsKKwlzd2l0Y2ggKGNoaXAtPmNoaXBfaWQpIHsKKwljYXNl
IFBNODYwN19DSElQX0EwOgorCWNhc2UgUE04NjA3X0NISVBfQTE6CisJCXJldCA9IHBtODYweF9z
ZXRfYml0cyhjaGlwLT5wYXJlbnQsIERFU0NfODYwNywKKwkJCQlQTTg2MDdfQTFfTUlTQzEsIG1h
c2ssIGRhdGEpOworCQlicmVhazsKKwljYXNlIFBNODYwN19DSElQX0IwOgorCWRlZmF1bHQ6CisJ
CWlmIChwZGF0YSkgeworCQkJLyoKKwkJCSAqIGlycV9tb2RlIGRlZmluZXMgdGhlIHdheSBvZiBj
bGVhcmluZyBpbnRlcnJ1cHQuIElmCisJCQkgKiBpdCdzIDEsIGNsZWFyIElSUSBieSB3cml0ZS4g
T3RoZXJ3aXNlLCBjbGVhciBpdCBieQorCQkJICogcmVhZC4KKwkJCSAqIFRoaXMgY29udHJvbCBi
aXQgaXMgdmFsaWQgZnJvbSA4OFBNODYwNyBCMCBzdGVwaW5nLgorCQkJICovCisJCQlpZiAoIXBk
YXRhLT5pcnFfbW9kZSkgeworCQkJCWRhdGEgPSAwOworCQkJCWNoaXAtPmlycV9tb2RlID0gMDsK
KwkJCX0KKwkJfQorCQlyZXQgPSBwbTg2MHhfc2V0X2JpdHMoY2hpcC0+cGFyZW50LCBERVNDXzg2
MDcsCisJCQkJUE04NjA3X0IwX01JU0MxLCBtYXNrLCBkYXRhKTsKKwkJYnJlYWs7CisJfQorCWlm
IChyZXQgPCAwKQorCQlnb3RvIG91dDsKKworCS8qIG1hc2sgYWxsIElSUXMgKi8KKwltZW1zZXQo
c3RhdHVzX2J1ZiwgMCwgSU5UX1NUQVRVU19OVU0pOworCXJldCA9IHBtODYweF9idWxrX3dyaXRl
KGNoaXAtPnBhcmVudCwgREVTQ184NjA3LCBQTTg2MDdfSU5UX01BU0tfMSwKKwkJCQlJTlRfU1RB
VFVTX05VTSwgc3RhdHVzX2J1Zik7CisJaWYgKHJldCA8IDApCisJCWdvdG8gb3V0OworCisJaWYg
KGNoaXAtPmlycV9tb2RlKSB7CisJCS8qIGNsZWFyIGludGVycnVwdCBzdGF0dXMgYnkgd3JpdGUg
Ki8KKwkJbWVtc2V0KHN0YXR1c19idWYsIDB4RkYsIElOVF9TVEFUVVNfTlVNKTsKKwkJcmV0ID0g
cG04NjB4X2J1bGtfd3JpdGUoY2hpcC0+cGFyZW50LCBERVNDXzg2MDcsCisJCQkJCVBNODYwN19J
TlRfU1RBVFVTMSwKKwkJCQkJSU5UX1NUQVRVU19OVU0sIHN0YXR1c19idWYpOworCX0gZWxzZSB7
CisJCS8qIGNsZWFyIGludGVycnVwdCBzdGF0dXMgYnkgcmVhZCAqLworCQlyZXQgPSBwbTg2MHhf
YnVsa19yZWFkKGNoaXAtPnBhcmVudCwgREVTQ184NjA3LAorCQkJCQlQTTg2MDdfSU5UX1NUQVRV
UzEsCisJCQkJCUlOVF9TVEFUVVNfTlVNLCBzdGF0dXNfYnVmKTsKKwl9CisJaWYgKHJldCA8IDAp
CisJCWdvdG8gb3V0OworCisJbWVtc2V0KGNoaXAtPmlycSwgMCwgc2l6ZW9mKHN0cnVjdCBwbTg2
MHhfaXJxKSAqIFBNODYwWF9OVU1fSVJRKTsKKworCWlmIChjaGlwLT5jbGllbnQgPT0gTlVMTCkK
KwkJZ290byBvdXQ7CisKKwlpcnEgPSBjaGlwLT5jbGllbnQtPmlycTsKKwlyZXQgPSByZXF1ZXN0
X3RocmVhZGVkX2lycShpcnEsIE5VTEwsIHBtODYwN19pcnFfdGhyZWFkLAorCQkJCUlSUUZfT05F
U0hPVCB8IElSUUZfVFJJR0dFUl9MT1csCisJCQkJIjg4cG04NjA3IiwgY2hpcCk7CisJaWYgKHJl
dCA8IDApIHsKKwkJZGV2X2VycihjaGlwLT5kZXYsICJGYWlsZWQgdG8gcmVxdWVzdCBJUlEgIyVk
LlxuIiwgaXJxKTsKKwkJZ290byBvdXQ7CisJfQorCWNoaXAtPmNoaXBfaXJxID0gcmV0OworCXJl
dHVybiAwOworb3V0OgorCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyB2b2lkIF9fZGV2ZXhpdCBf
Xzg4cG04NjB4X2lycV9leGl0KHN0cnVjdCBwbTg2MHhfY2hpcCAqY2hpcCkKK3sKKwlpZiAoY2hp
cC0+Y2hpcF9pcnEgPj0gMCkKKwkJZnJlZV9pcnEoY2hpcC0+Y2hpcF9pcnEsIGNoaXApOworfQor
CiBzdGF0aWMgaW50IF9fZGV2aW5pdCBfXzg4cG04NjA2X2luaXQoc3RydWN0IHBtODYweF9jaGlw
ICpjaGlwLCB2b2lkICpwZGF0YSkKIHsKIAljaGlwLT5wYXJlbnQgPSAmbWl4ZWRfY2hpcDsKIAlt
aXhlZF9jaGlwLnBtODYwNiA9IGNoaXA7CisJY2hpcC0+Y2hpcF9pcnEgPSAtRUlOVkFMOwogCiAJ
cmV0dXJuIDA7CiB9CiAKIHN0YXRpYyBpbnQgX19kZXZpbml0IF9fODhwbTg2MDdfaW5pdChzdHJ1
Y3QgcG04NjB4X2NoaXAgKmNoaXAsCi0JCQkJICAgICBzdHJ1Y3QgcG04NjA3X3BsYXRfZGF0YSAq
cGRhdGEpCisJCQkJICAgICBzdHJ1Y3QgcG04NjB4X3BsYXRfZGF0YSAqcGRhdGEpCiB7Ci0JaW50
IHJldCA9IDA7CisJaW50IGRhdGEgPSAwLCByZXQgPSAwOwogCiAJY2hpcC0+cGFyZW50ID0gJm1p
eGVkX2NoaXA7CiAJbWl4ZWRfY2hpcC5wbTg2MDcgPSBjaGlwOworCWNoaXAtPmNoaXBfaXJxID0g
LUVJTlZBTDsKIAogCXJldCA9IHBtODYweF9yZWdfcmVhZChjaGlwLT5wYXJlbnQsIERFU0NfODYw
NywgUE04NjA3X0NISVBfSUQpOwogCWlmIChyZXQgPCAwKSB7CkBAIC0xMDgsMjAgKzMxNiwzMCBA
QCBzdGF0aWMgaW50IF9fZGV2aW5pdCBfXzg4cG04NjA3X2luaXQoc3RydWN0IHBtODYweF9jaGlw
ICpjaGlwLAogCWlmIChyZXQgJiBQTTg2MDdfQlVDSzNfRE9VQkxFKQogCQljaGlwLT5wYXJlbnQt
PmJ1Y2szX2RvdWJsZSA9IDE7CiAKLQlyZXQgPSBwbTg2MHhfcmVnX3JlYWQoY2hpcC0+cGFyZW50
LCBERVNDXzg2MDcsIFBNODYwN19NSVNDMSk7Ci0JaWYgKHJldCA8IDApIHsKLQkJZGV2X2Vycihj
aGlwLT5kZXYsICJGYWlsZWQgdG8gcmVhZCBNSVNDMSByZWdpc3RlcjogJWRcbiIsIHJldCk7Ci0J
CWdvdG8gb3V0OworCWlmIChwZGF0YSAmJiAocGRhdGEtPmkyY19wb3J0ID09IFBJMkNfUE9SVCkp
IHsKKwkJc3dpdGNoIChjaGlwLT5jaGlwX2lkKSB7CisJCWNhc2UgUE04NjA3X0NISVBfQTA6CisJ
CWNhc2UgUE04NjA3X0NISVBfQTE6CisJCQlkYXRhID0gUE04NjA3X0ExX01JU0MxX1BJMkM7CisJ
CQlyZXQgPSBwbTg2MHhfc2V0X2JpdHMoY2hpcC0+cGFyZW50LCBERVNDXzg2MDcsCisJCQkJCVBN
ODYwN19BMV9NSVNDMSwgZGF0YSwgZGF0YSk7CisJCQlicmVhazsKKwkJY2FzZSBQTTg2MDdfQ0hJ
UF9CMDoKKwkJZGVmYXVsdDoKKwkJCWRhdGEgPSBQTTg2MDdfQjBfTUlTQzFfUEkyQzsKKwkJCXJl
dCA9IHBtODYweF9zZXRfYml0cyhjaGlwLT5wYXJlbnQsIERFU0NfODYwNywKKwkJCQkJUE04NjA3
X0IwX01JU0MxLCBkYXRhLCBkYXRhKTsKKwkJCWJyZWFrOworCQl9CisJCWlmIChyZXQgPCAwKSB7
CisJCQlkZXZfZXJyKGNoaXAtPmRldiwgIkZhaWxlZCB0byBhY2Nlc3MgTUlTQzE6JWRcbiIsIHJl
dCk7CisJCQlnb3RvIG91dDsKKwkJfQogCX0KLQlpZiAocGRhdGEgJiYgKHBkYXRhLT5pMmNfcG9y
dCA9PSBQSTJDX1BPUlQpKQotCQlyZXQgfD0gUE04NjA3X01JU0MxX1BJMkM7Ci0JZWxzZQotCQly
ZXQgJj0gflBNODYwN19NSVNDMV9QSTJDOwotCXJldCA9IHBtODYweF9yZWdfd3JpdGUoY2hpcC0+
cGFyZW50LCBERVNDXzg2MDcsIFBNODYwN19NSVNDMSwgcmV0KTsKLQlpZiAocmV0IDwgMCkgewot
CQlkZXZfZXJyKGNoaXAtPmRldiwgIkZhaWxlZCB0byB3cml0ZSBNSVNDMSByZWdpc3RlcjogJWRc
biIsIHJldCk7CisKKwlyZXQgPSBfXzg4cG04NjA3X2lycV9pbml0KGNoaXAsIHBkYXRhKTsKKwlp
ZiAocmV0IDwgMCkKIAkJZ290byBvdXQ7Ci0JfQogb3V0OgogCXJldHVybiByZXQ7CiB9CkBAIC0x
MzYsNyArMzU0LDcgQEAgaW50IF9fZGV2aW5pdCBwbTg2MHhfZGV2aWNlX2luaXQoc3RydWN0IHBt
ODYweF9jaGlwICpjaGlwLCB2b2lkICpwZGF0YSkKIAkJbXV0ZXhfaW5pdCgmbWl4ZWRfY2hpcC5p
b19sb2NrKTsKIAogCWlmICghc3RyY21wKGNoaXAtPmlkLm5hbWUsICI4OFBNODYwNyIpKSB7Ci0J
CXJldCA9IF9fODhwbTg2MDdfaW5pdChjaGlwLCAoc3RydWN0IHBtODYwN19wbGF0X2RhdGEgKilw
ZGF0YSk7CisJCXJldCA9IF9fODhwbTg2MDdfaW5pdChjaGlwLCAoc3RydWN0IHBtODYweF9wbGF0
X2RhdGEgKilwZGF0YSk7CiAJCWlmIChyZXQgPCAwKQogCQkJZ290byBvdXQ7CiAKQEAgLTE2MCw2
ICszNzgsNyBAQCBvdXQ6CiAKIHZvaWQgX19kZXZleGl0IHBtODYwN19kZXZpY2VfZXhpdChzdHJ1
Y3QgcG04NjB4X2NoaXAgKmNoaXApCiB7CisJX184OHBtODYweF9pcnFfZXhpdChjaGlwKTsKIAlt
ZmRfcmVtb3ZlX2RldmljZXMoY2hpcC0+ZGV2KTsKIH0KIApkaWZmIC0tZ2l0IGEvaW5jbHVkZS9s
aW51eC9tZmQvODhwbTg2MHguaCBiL2luY2x1ZGUvbGludXgvbWZkLzg4cG04NjB4LmgKaW5kZXgg
ZmQ4ZThhZC4uOTlhNWE3ZSAxMDA2NDQKLS0tIGEvaW5jbHVkZS9saW51eC9tZmQvODhwbTg2MHgu
aAorKysgYi9pbmNsdWRlL2xpbnV4L21mZC84OHBtODYweC5oCkBAIC0xMiw2ICsxMiw4IEBACiAj
aWZuZGVmIF9fTElOVVhfTUZEXzg4UE04NjBYX0gKICNkZWZpbmUgX19MSU5VWF9NRkRfODhQTTg2
MFhfSAogCisjaW5jbHVkZSA8bGludXgvaW50ZXJydXB0Lmg+CisKIGVudW0gewogCURFU0NfSU5W
QUwgPSAwLAogCURFU0NfODYwNiwKQEAgLTEwOSwzMyArMTExLDEwIEBAIGVudW0gewogCiAvKiBN
aXNjIFJlZ2lzdGVycyAqLwogI2RlZmluZSBQTTg2MDdfQ0hJUF9JRAkJCSgweDAwKQorI2RlZmlu
ZSBQTTg2MDdfQjBfTUlTQzEJCQkoMHgwQykKICNkZWZpbmUgUE04NjA3X0xETzEJCQkoMHgxMCkK
ICNkZWZpbmUgUE04NjA3X0RWQzMJCQkoMHgyNikKLSNkZWZpbmUgUE04NjA3X01JU0MxCQkJKDB4
NDApCi0KLS8qIGJpdCBkZWZpbml0aW9ucyBmb3IgUE04NjA3IGV2ZW50cyAqLwotI2RlZmluZSBQ
TTg2MDdfRVZFTlRfT05LRVkJCSgxIDw8IDApCi0jZGVmaW5lIFBNODYwN19FVkVOVF9FWFRPTgkJ
KDEgPDwgMSkKLSNkZWZpbmUgUE04NjA3X0VWRU5UX0NIRwkJKDEgPDwgMikKLSNkZWZpbmUgUE04
NjA3X0VWRU5UX0JBVAkJKDEgPDwgMykKLSNkZWZpbmUgUE04NjA3X0VWRU5UX1JUQwkJKDEgPDwg
NCkKLSNkZWZpbmUgUE04NjA3X0VWRU5UX0NDCQkJKDEgPDwgNSkKLSNkZWZpbmUgUE04NjA3X0VW
RU5UX1ZCQVQJCSgxIDw8IDgpCi0jZGVmaW5lIFBNODYwN19FVkVOVF9WQ0hHCQkoMSA8PCA5KQot
I2RlZmluZSBQTTg2MDdfRVZFTlRfVlNZUwkJKDEgPDwgMTApCi0jZGVmaW5lIFBNODYwN19FVkVO
VF9USU5UCQkoMSA8PCAxMSkKLSNkZWZpbmUgUE04NjA3X0VWRU5UX0dQQURDMAkJKDEgPDwgMTIp
Ci0jZGVmaW5lIFBNODYwN19FVkVOVF9HUEFEQzEJCSgxIDw8IDEzKQotI2RlZmluZSBQTTg2MDdf
RVZFTlRfR1BBREMyCQkoMSA8PCAxNCkKLSNkZWZpbmUgUE04NjA3X0VWRU5UX0dQQURDMwkJKDEg
PDwgMTUpCi0jZGVmaW5lIFBNODYwN19FVkVOVF9BVURJT19TSE9SVAkoMSA8PCAxNikKLSNkZWZp
bmUgUE04NjA3X0VWRU5UX1BFTgkJKDEgPDwgMTcpCi0jZGVmaW5lIFBNODYwN19FVkVOVF9IRUFE
U0VUCQkoMSA8PCAxOCkKLSNkZWZpbmUgUE04NjA3X0VWRU5UX0hPT0sJCSgxIDw8IDE5KQotI2Rl
ZmluZSBQTTg2MDdfRVZFTlRfTUlDSU4JCSgxIDw8IDIwKQotI2RlZmluZSBQTTg2MDdfRVZFTlRf
Q0hHX1RJTUVPVVQJKDEgPDwgMjEpCi0jZGVmaW5lIFBNODYwN19FVkVOVF9DSEdfRE9ORQkJKDEg
PDwgMjIpCi0jZGVmaW5lIFBNODYwN19FVkVOVF9DSEdfRkFVTFQJCSgxIDw8IDIzKQorI2RlZmlu
ZSBQTTg2MDdfQTFfTUlTQzEJCQkoMHg0MCkKIAogLyogYml0IGRlZmluaXRpb25zIG9mIFN0YXR1
cyBRdWVyeSBJbnRlcmZhY2UgKi8KICNkZWZpbmUgUE04NjA3X1NUQVRVU19DQwkJKDEgPDwgMykK
QEAgLTE1NCw3ICsxMzMsMTIgQEAgZW51bSB7CiAjZGVmaW5lIFBNODYwN19CVUNLM19ET1VCTEUJ
CSgxIDw8IDYpCiAKIC8qIGJpdCBkZWZpbml0aW9ucyBvZiBNaXNjMSAqLwotI2RlZmluZSBQTTg2
MDdfTUlTQzFfUEkyQwkJKDEgPDwgMCkKKyNkZWZpbmUgUE04NjA3X0ExX01JU0MxX1BJMkMJCSgx
IDw8IDApCisjZGVmaW5lIFBNODYwN19CMF9NSVNDMV9JTlZfSU5UCQkoMSA8PCAwKQorI2RlZmlu
ZSBQTTg2MDdfQjBfTUlTQzFfSU5UX0NMRUFSCSgxIDw8IDEpCisjZGVmaW5lIFBNODYwN19CMF9N
SVNDMV9JTlRfTUFTSwkoMSA8PCAyKQorI2RlZmluZSBQTTg2MDdfQjBfTUlTQzFfUEkyQwkJKDEg
PDwgMykKKyNkZWZpbmUgUE04NjA3X0IwX01JU0MxX1JFU0VUCQkoMSA8PCA2KQogCiAvKiBJbnRl
cnJ1cHQgTnVtYmVyIGluIDg4UE04NjA3ICovCiBlbnVtIHsKQEAgLTE5OSwxNCArMTgzLDI1IEBA
IHN0cnVjdCBtaXhlZF84OHBtODYweCB7CiAJaW50CQkJZmxhZ3M7CiB9OwogCisjZGVmaW5lIFBN
ODYwWF9OVU1fSVJRCQkyNAorCitzdHJ1Y3QgcG04NjB4X2lycSB7CisJaXJxX2hhbmRsZXJfdAkJ
aGFuZGxlcjsKKwl2b2lkCQkJKmRhdGE7Cit9OworCiBzdHJ1Y3QgcG04NjB4X2NoaXAgewogCXN0
cnVjdCBkZXZpY2UJCSpkZXY7Ci0Jc3RydWN0IG11dGV4CQlpb19sb2NrOwogCXN0cnVjdCBpMmNf
Y2xpZW50CSpjbGllbnQ7CiAJc3RydWN0IGkyY19kZXZpY2VfaWQJaWQ7CiAJc3RydWN0IG1peGVk
Xzg4cG04NjB4CSpwYXJlbnQ7CisJc3RydWN0IG11dGV4CQlpcnFfbG9jazsKKwlpbnQJCQljaGlw
X2lycTsKIAl1bnNpZ25lZCBjaGFyCQljaGlwX2lkOwogCisJc3RydWN0IHBtODYweF9pcnEJaXJx
W1BNODYwWF9OVU1fSVJRXTsKKwlpbnQJCQlpcnFfbW9kZTsKKwogCWludCAoKnJlYWQpKHN0cnVj
dCBwbTg2MHhfY2hpcCAqY2hpcCwgaW50IHJlZywgaW50IGJ5dGVzLCB2b2lkICpkZXN0KTsKIAlp
bnQgKCp3cml0ZSkoc3RydWN0IHBtODYweF9jaGlwICpjaGlwLCBpbnQgcmVnLCBpbnQgYnl0ZXMs
IHZvaWQgKnNyYyk7CiB9OwpAQCAtMjE4LDggKzIxMyw5IEBAIGVudW0gewogCVBJMkNfUE9SVCwK
IH07CiAKLXN0cnVjdCBwbTg2MDdfcGxhdF9kYXRhIHsKK3N0cnVjdCBwbTg2MHhfcGxhdF9kYXRh
IHsKIAlpbnQJaTJjX3BvcnQ7CS8qIENvbnRyb2xsZWQgYnkgR0kyQyBvciBQSTJDICovCisJaW50
CWlycV9tb2RlOwkvKiBDbGVhciBpbnRlcnJ1cHQgYnkgcmVhZC93cml0ZSAoMS8wKSAqLwogCXN0
cnVjdCByZWd1bGF0b3JfaW5pdF9kYXRhICpyZWd1bGF0b3JbUE04NjA3X01BWF9SRUdVTEFUT1Jd
OwogfTsKIApAQCAtMjMyLDYgKzIyOCwxMiBAQCBleHRlcm4gaW50IHBtODYweF9idWxrX3dyaXRl
KHN0cnVjdCBtaXhlZF84OHBtODYweCAqLCBpbnQsIGludCwgaW50LAogZXh0ZXJuIGludCBwbTg2
MHhfc2V0X2JpdHMoc3RydWN0IG1peGVkXzg4cG04NjB4ICosIGludCwgaW50LCB1bnNpZ25lZCBj
aGFyLAogCQkJICAgdW5zaWduZWQgY2hhcik7CiAKK2V4dGVybiBpbnQgcG04NjB4X21hc2tfaXJx
KHN0cnVjdCBwbTg2MHhfY2hpcCAqLCBpbnQpOworZXh0ZXJuIGludCBwbTg2MHhfdW5tYXNrX2ly
cShzdHJ1Y3QgcG04NjB4X2NoaXAgKiwgaW50KTsKK2V4dGVybiBpbnQgcG04NjB4X3JlcXVlc3Rf
aXJxKHN0cnVjdCBwbTg2MHhfY2hpcCAqLCBpbnQsCisJCQkgICAgICBpcnFfaGFuZGxlcl90IGhh
bmRsZXIsIHZvaWQgKik7CitleHRlcm4gaW50IHBtODYweF9mcmVlX2lycShzdHJ1Y3QgcG04NjB4
X2NoaXAgKiwgaW50KTsKKwogZXh0ZXJuIGludCBwbTg2MHhfZGV2aWNlX2luaXQoc3RydWN0IHBt
ODYweF9jaGlwICpjaGlwLCB2b2lkICpwZGF0YSk7CiBleHRlcm4gdm9pZCBwbTg2MHhfZGV2aWNl
X2V4aXQoc3RydWN0IHBtODYweF9jaGlwICpjaGlwKTsKIAotLSAKMS41LjYuNQoK
--00151773da30083edf04788b4bfe--



More information about the linux-arm-kernel mailing list