From: Andy Green <[EMAIL PROTECTED]>

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 <[EMAIL PROTECTED]>
---

 drivers/i2c/chips/pcf50606.c |   60 ++++++++++++++++++++++++------------------
 1 files changed, 34 insertions(+), 26 deletions(-)


diff --git a/drivers/i2c/chips/pcf50606.c b/drivers/i2c/chips/pcf50606.c
index def2d35..970a523 100644
--- a/drivers/i2c/chips/pcf50606.c
+++ b/drivers/i2c/chips/pcf50606.c
@@ -563,25 +563,33 @@ static void pcf50606_work(struct work_struct *work)
 {
        struct pcf50606_data *pcf =
                        container_of(work, struct pcf50606_data, work);
-       u_int8_t int1, int2, int3;
+       u_int8_t pcfirq[3];
+       int ret;
 
        mutex_lock(&pcf->working_lock);
        pcf->working = 1;
-
-       int1 = __reg_read(pcf, PCF50606_REG_INT1);
-       int2 = __reg_read(pcf, PCF50606_REG_INT2);
-       int3 = __reg_read(pcf, PCF50606_REG_INT3);
+       /*
+        * p35 pcf50606 datasheet rev 2.2:
+        * ''The system controller shall read all interrupt registers in
+        *   one I2C read action''
+        * because if you don't INT# gets stuck asserted forever after a
+        * while
+        */
+       ret = i2c_smbus_read_i2c_block_data(&pcf->client, PCF50606_REG_INT1, 3,
+                                           pcfirq);
+       if (ret != 3)
+               DEBUGPC("Oh crap PMU IRQ register read failed %d\n", ret);
 
        dev_dbg(&pcf->client.dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x:",
-               int1, int2, int3);
+               pcfirq[0], pcfirq[1], pcfirq[2]);
 
-       if (int1 & PCF50606_INT1_ONKEYF) {
+       if (pcfirq[0] & PCF50606_INT1_ONKEYF) {
                /* ONKEY falling edge (start of button press) */
                DEBUGPC("ONKEYF ");
                pcf->flags |= PCF50606_F_PWR_PRESSED;
                input_report_key(pcf->input_dev, KEY_POWER, 1);
        }
-       if (int1 & PCF50606_INT1_ONKEY1S) {
+       if (pcfirq[0] & PCF50606_INT1_ONKEY1S) {
                /* ONKEY pressed for more than 1 second */
                pcf->onkey_seconds = 0;
                DEBUGPC("ONKEY1S ");
@@ -592,7 +600,7 @@ static void pcf50606_work(struct work_struct *work)
                /* enable SECOND interrupt (hz tick) */
                reg_clear_bits(pcf, PCF50606_REG_INT1M, PCF50606_INT1_SECOND);
        }
-       if (int1 & PCF50606_INT1_ONKEYR) {
+       if (pcfirq[0] & PCF50606_INT1_ONKEYR) {
                /* ONKEY rising edge (end of button press) */
                DEBUGPC("ONKEYR ");
                pcf->flags &= ~PCF50606_F_PWR_PRESSED;
@@ -605,15 +613,15 @@ static void pcf50606_work(struct work_struct *work)
                                         PCF50606_INT1_SECOND,
                                         PCF50606_INT1_SECOND);
        }
-       if (int1 & PCF50606_INT1_EXTONR) {
+       if (pcfirq[0] & PCF50606_INT1_EXTONR) {
                DEBUGPC("EXTONR ");
                input_report_key(pcf->input_dev, KEY_POWER2, 1);
        }
-       if (int1 & PCF50606_INT1_EXTONF) {
+       if (pcfirq[0] & PCF50606_INT1_EXTONF) {
                DEBUGPC("EXTONF ");
                input_report_key(pcf->input_dev, KEY_POWER2, 0);
        }
-       if (int1 & PCF50606_INT1_SECOND) {
+       if (pcfirq[0] & PCF50606_INT1_SECOND) {
                DEBUGPC("SECOND ");
                if (pcf->flags & PCF50606_F_RTC_SECOND)
                        rtc_update_irq(pcf->rtc, 1,
@@ -635,14 +643,14 @@ static void pcf50606_work(struct work_struct *work)
                        }
                }
        }
-       if (int1 & PCF50606_INT1_ALARM) {
+       if (pcfirq[0] & PCF50606_INT1_ALARM) {
                DEBUGPC("ALARM ");
                if (pcf->pdata->used_features & PCF50606_FEAT_RTC)
                        rtc_update_irq(pcf->rtc, 1,
                                       RTC_AF | RTC_IRQF);
        }
 
-       if (int2 & PCF50606_INT2_CHGINS) {
+       if (pcfirq[1] & PCF50606_INT2_CHGINS) {
                /* Charger inserted */
                DEBUGPC("CHGINS ");
                input_report_key(pcf->input_dev, KEY_BATTERY, 1);
@@ -653,7 +661,7 @@ static void pcf50606_work(struct work_struct *work)
                                       PCF50606_FEAT_MBC, PMU_EVT_INSERT);
                /* FIXME: how to signal this to userspace */
        }
-       if (int2 & PCF50606_INT2_CHGRM) {
+       if (pcfirq[1] & PCF50606_INT2_CHGRM) {
                /* Charger removed */
                DEBUGPC("CHGRM ");
                input_report_key(pcf->input_dev, KEY_BATTERY, 0);
@@ -664,57 +672,57 @@ static void pcf50606_work(struct work_struct *work)
                                       PCF50606_FEAT_MBC, PMU_EVT_INSERT);
                /* FIXME: how signal this to userspace */
        }
-       if (int2 & PCF50606_INT2_CHGFOK) {
+       if (pcfirq[1] & PCF50606_INT2_CHGFOK) {
                /* Battery ready for fast charging */
                DEBUGPC("CHGFOK ");
                pcf->flags |= PCF50606_F_CHG_FOK;
                /* FIXME: how to signal this to userspace */
        }
-       if (int2 & PCF50606_INT2_CHGERR) {
+       if (pcfirq[1] & PCF50606_INT2_CHGERR) {
                /* Error in charge mode */
                DEBUGPC("CHGERR ");
                pcf->flags |= PCF50606_F_CHG_ERR;
                pcf->flags &= ~(PCF50606_F_CHG_FOK|PCF50606_F_CHG_READY);
                /* FIXME: how to signal this to userspace */
        }
-       if (int2 & PCF50606_INT2_CHGFRDY) {
+       if (pcfirq[1] & PCF50606_INT2_CHGFRDY) {
                /* Fast charge completed */
                DEBUGPC("CHGFRDY ");
                pcf->flags |= PCF50606_F_CHG_READY;
                pcf->flags &= ~PCF50606_F_CHG_FOK;
                /* FIXME: how to signal this to userspace */
        }
-       if (int2 & PCF50606_INT2_CHGPROT) {
+       if (pcfirq[1] & PCF50606_INT2_CHGPROT) {
                /* Charging protection interrupt */
                DEBUGPC("CHGPROT ");
                pcf->flags &= ~(PCF50606_F_CHG_FOK|PCF50606_F_CHG_READY);
                /* FIXME: signal this to userspace */
        }
-       if (int2 & PCF50606_INT2_CHGWD10S) {
+       if (pcfirq[1] & PCF50606_INT2_CHGWD10S) {
                /* Charger watchdog will expire in 10 seconds */
                DEBUGPC("CHGWD10S ");
                reg_set_bit_mask(pcf, PCF50606_REG_OOCC1,
                                 PCF50606_OOCC1_WDTRST,
                                 PCF50606_OOCC1_WDTRST);
        }
-       if (int2 & PCF50606_INT2_CHGWDEXP) {
+       if (pcfirq[1] & PCF50606_INT2_CHGWDEXP) {
                /* Charger watchdog expires */
                DEBUGPC("CHGWDEXP ");
                /* FIXME: how to signal this to userspace */
        }
 
-       if (int3 & PCF50606_INT3_ADCRDY) {
+       if (pcfirq[2] & PCF50606_INT3_ADCRDY) {
                /* ADC result ready */
                DEBUGPC("ADCRDY ");
        }
-       if (int3 & PCF50606_INT3_ACDINS) {
+       if (pcfirq[2] & PCF50606_INT3_ACDINS) {
                /* Accessory insertion detected */
                DEBUGPC("ACDINS ");
                if (pcf->pdata->cb)
                        pcf->pdata->cb(&pcf->client.dev,
                                       PCF50606_FEAT_ACD, PMU_EVT_INSERT);
        }
-       if (int3 & PCF50606_INT3_ACDREM) {
+       if (pcfirq[2] & PCF50606_INT3_ACDREM) {
                /* Accessory removal detected */
                DEBUGPC("ACDREM ");
                if (pcf->pdata->cb)
@@ -722,7 +730,7 @@ static void pcf50606_work(struct work_struct *work)
                                       PCF50606_FEAT_ACD, PMU_EVT_REMOVE);
        }
        /* FIXME: TSCPRES */
-       if (int3 & PCF50606_INT3_LOWBAT) {
+       if (pcfirq[2] & PCF50606_INT3_LOWBAT) {
                /* Really low battery voltage, we have 8 seconds left */
                DEBUGPC("LOWBAT ");
                apm_queue_event(APM_LOW_BATTERY);
@@ -733,7 +741,7 @@ static void pcf50606_work(struct work_struct *work)
                                 PCF50606_OOCC1_TOTRST,
                                 PCF50606_OOCC1_TOTRST);
        }
-       if (int3 & PCF50606_INT3_HIGHTMP) {
+       if (pcfirq[2] & PCF50606_INT3_HIGHTMP) {
                /* High temperature */
                DEBUGPC("HIGHTMP ");
                apm_queue_event(APM_CRITICAL_SUSPEND);


Reply via email to