[PATCH 03/10] fix-pcf50633-atomic-i2c-int-read.patch

warmcat andy at openmoko.com
Mon Feb 11 17:34:35 CET 2008


From: Andy Green <andy at openmoko.com>

Datasheet says reading the interrupt source regs (and thereby
clearing them) must be done in a single i2c read transaction

Signed-off-by: Andy Green <andy at openmoko.com>
---

 drivers/i2c/chips/pcf50633.c |   58 ++++++++++++++++++++++--------------------
 1 files changed, 30 insertions(+), 28 deletions(-)


diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
index e68b712..78b4a2d 100644
--- a/drivers/i2c/chips/pcf50633.c
+++ b/drivers/i2c/chips/pcf50633.c
@@ -489,22 +489,24 @@ static void pcf50633_work(struct work_struct *work)
 {
 	struct pcf50633_data *pcf =
 			container_of(work, struct pcf50633_data, work);
-	u_int8_t int1, int2, int3, int4, int5;
+	u_int8_t pcfirq[5];
+	int ret;
 
 	mutex_lock(&pcf->working_lock);
 	pcf->working = 1;
-
-	/* FIXME: read in one i2c transaction */
-	int1 = __reg_read(pcf, PCF50633_REG_INT1);
-	int2 = __reg_read(pcf, PCF50633_REG_INT2);
-	int3 = __reg_read(pcf, PCF50633_REG_INT3);
-	int4 = __reg_read(pcf, PCF50633_REG_INT4);
-	int5 = __reg_read(pcf, PCF50633_REG_INT5);
+	/*
+	 * datasheet says we have to read the five IRQ
+	 * status regs in one transaction
+	 */
+	ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50633_REG_INT1, 5,
+					    pcfirq);
+	if (ret != 5)
+		DEBUGP("Oh crap PMU IRQ register read failed %d\n", ret);
 
 	DEBUGP("INT1=0x%02x INT2=0x%02x INT3=0x%02x INT4=0x%02x INT5=0x%02x\n",
-		int1, int2, int3, int4, int5);
+		pcfirq[0], pcfirq[1], pcfirq[2], pcfirq[3], pcfirq[4]);
 
-	if (int1 & PCF50633_INT1_ADPINS) {
+	if (pcfirq[0] & PCF50633_INT1_ADPINS) {
 		/* Charger inserted */
 		DEBUGPC("ADPINS ");
 		input_report_key(pcf->input_dev, KEY_BATTERY, 1);
@@ -516,7 +518,7 @@ static void pcf50633_work(struct work_struct *work)
 		/* FIXME: signal this to userspace */
 		//kobject_uevent( ,KOBJ_ADD);
 	}
-	if (int1 & PCF50633_INT1_ADPREM) {
+	if (pcfirq[0] & PCF50633_INT1_ADPREM) {
 		/* Charger removed */
 		DEBUGPC("ADPREM ");
 		input_report_key(pcf->input_dev, KEY_BATTERY, 0);
@@ -528,7 +530,7 @@ static void pcf50633_work(struct work_struct *work)
 		/* FIXME: signal this to userspace */
 		//kobject_uevent( ,KOBJ_ADD);
 	}
-	if (int1 & PCF50633_INT1_USBINS) {
+	if (pcfirq[0] & PCF50633_INT1_USBINS) {
 		DEBUGPC("USBINS ");
 		input_report_key(pcf->input_dev, KEY_POWER2, 1);
 		apm_queue_event(APM_POWER_STATUS_CHANGE);
@@ -538,7 +540,7 @@ static void pcf50633_work(struct work_struct *work)
 				       PCF50633_FEAT_MBC, PMU_EVT_USB_INSERT);
 
 	}
-	if (int1 & PCF50633_INT1_USBREM) {
+	if (pcfirq[0] & PCF50633_INT1_USBREM) {
 		DEBUGPC("USBREM ");
 		input_report_key(pcf->input_dev, KEY_POWER2, 0);
 		apm_queue_event(APM_POWER_STATUS_CHANGE);
@@ -547,13 +549,13 @@ static void pcf50633_work(struct work_struct *work)
 			pcf->pdata->cb(&pcf->client.dev,
 				       PCF50633_FEAT_MBC, PMU_EVT_USB_REMOVE);
 	}
-	if (int1 & PCF50633_INT1_ALARM) {
+	if (pcfirq[0] & PCF50633_INT1_ALARM) {
 		DEBUGPC("ALARM ");
 		if (pcf->pdata->used_features & PCF50633_FEAT_RTC)
 			rtc_update_irq(pcf->rtc, 1,
 				       RTC_AF | RTC_IRQF);
 	}
-	if (int1 & PCF50633_INT1_SECOND) {
+	if (pcfirq[0] & PCF50633_INT1_SECOND) {
 		DEBUGPC("SECOND ");
 		if (pcf->flags & PCF50633_F_RTC_SECOND)
 			rtc_update_irq(pcf->rtc, 1,
@@ -575,13 +577,13 @@ static void pcf50633_work(struct work_struct *work)
 		}
 	}
 
-	if (int2 & PCF50633_INT2_ONKEYF) {
+	if (pcfirq[1] & PCF50633_INT2_ONKEYF) {
 		/* ONKEY falling edge (start of button press) */
 		DEBUGPC("ONKEYF ");
 		pcf->flags |= PCF50633_F_PWR_PRESSED;
 		input_report_key(pcf->input_dev, KEY_POWER, 1);
 	}
-	if (int2 & PCF50633_INT2_ONKEYR) {
+	if (pcfirq[1] & PCF50633_INT2_ONKEYR) {
 		/* ONKEY rising edge (end of button press) */
 		DEBUGPC("ONKEYR ");
 		pcf->flags &= ~PCF50633_F_PWR_PRESSED;
@@ -596,37 +598,37 @@ static void pcf50633_work(struct work_struct *work)
 	}
 	/* FIXME: we don't use EXTON1/2/3. thats why we skip it */
 
-	if (int3 & PCF50633_INT3_BATFULL) {
+	if (pcfirq[2] & PCF50633_INT3_BATFULL) {
 		DEBUGPC("BATFULL ");
 		/* FIXME: signal this to userspace */
 	}
-	if (int3 & PCF50633_INT3_CHGHALT) {
+	if (pcfirq[2] & PCF50633_INT3_CHGHALT) {
 		DEBUGPC("CHGHALT ");
 		/* FIXME: signal this to userspace */
 	}
-	if (int3 & PCF50633_INT3_THLIMON) {
+	if (pcfirq[2] & PCF50633_INT3_THLIMON) {
 		DEBUGPC("THLIMON ");
 		pcf->flags |= PCF50633_F_CHG_PROT;
 		/* FIXME: signal this to userspace */
 	}
-	if (int3 & PCF50633_INT3_THLIMOFF) {
+	if (pcfirq[2] & PCF50633_INT3_THLIMOFF) {
 		DEBUGPC("THLIMOFF ");
 		pcf->flags &= ~PCF50633_F_CHG_PROT;
 		/* FIXME: signal this to userspace */
 	}
-	if (int3 & PCF50633_INT3_USBLIMON) {
+	if (pcfirq[2] & PCF50633_INT3_USBLIMON) {
 		DEBUGPC("USBLIMON ");
 		/* FIXME: signal this to userspace */
 	}
-	if (int3 & PCF50633_INT3_USBLIMOFF) {
+	if (pcfirq[2] & PCF50633_INT3_USBLIMOFF) {
 		DEBUGPC("USBLIMOFF ");
 		/* FIXME: signal this to userspace */
 	}
-	if (int3 & PCF50633_INT3_ADCRDY) {
+	if (pcfirq[2] & PCF50633_INT3_ADCRDY) {
 		/* ADC result ready */
 		DEBUGPC("ADCRDY ");
 	}
-	if (int3 & PCF50633_INT3_ONKEY1S) {
+	if (pcfirq[2] & PCF50633_INT3_ONKEY1S) {
 		/* ONKEY pressed for more than 1 second */
 		pcf->onkey_seconds = 0;
 		DEBUGPC("ONKEY1S ");
@@ -638,7 +640,7 @@ static void pcf50633_work(struct work_struct *work)
 		reg_clear_bits(pcf, PCF50633_REG_INT1M, PCF50633_INT1_SECOND);
 	}
 
-	if (int4 & (PCF50633_INT4_LOWBAT|PCF50633_INT4_LOWSYS)) {
+	if (pcfirq[3] & (PCF50633_INT4_LOWBAT|PCF50633_INT4_LOWSYS)) {
 		/* Really low battery voltage, we have 8 seconds left */
 		DEBUGPC("LOWBAT ");
 		apm_queue_event(APM_LOW_BATTERY);
@@ -649,12 +651,12 @@ static void pcf50633_work(struct work_struct *work)
 				 PCF50633_OOCSHDWN_TOTRST,
 				 PCF50633_OOCSHDWN_TOTRST);
 	}
-	if (int4 & PCF50633_INT4_HIGHTMP) {
+	if (pcfirq[3] & PCF50633_INT4_HIGHTMP) {
 		/* High temperature */
 		DEBUGPC("HIGHTMP ");
 		apm_queue_event(APM_CRITICAL_SUSPEND);
 	}
-	if (int4 & (PCF50633_INT4_AUTOPWRFAIL|PCF50633_INT4_DWN1PWRFAIL|
+	if (pcfirq[3] & (PCF50633_INT4_AUTOPWRFAIL|PCF50633_INT4_DWN1PWRFAIL|
 		   PCF50633_INT4_DWN2PWRFAIL|PCF50633_INT4_LEDPWRFAIL|
 		   PCF50633_INT4_LEDOVP)) {
 		/* Some regulator failed */





More information about the openmoko-kernel mailing list