ARM: PXA2xx: MFP: fix bug with MFP_LPM_KEEP_OUTPUT
authorIgor Grinberg <grinberg@compulab.co.il>
Thu, 12 Apr 2012 12:43:28 +0000 (15:43 +0300)
committerHaojian Zhuang <haojian.zhuang@gmail.com>
Fri, 27 Apr 2012 03:11:50 +0000 (11:11 +0800)
Pins that have MFP_LPM_KEEP_OUTPUT set and are configured for output
must retain the output state in low power mode.
Currently, the pin direction configuration is overrided with values
in gpdr_lpm[] array and do not obey the MFP_LPM_KEEP_OUTPUT setting.

Fix the above bug and add some documentation to clarify the
MFP_LPM_KEEP_OUTPUT setting purpose.

Reported-by: Paul Parsons <lost.distance@yahoo.com>
Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
Tested-by: Paul Parsons <lost.distance@yahoo.com>
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
arch/arm/mach-pxa/mfp-pxa2xx.c

index c54cef25895cdbbbe03c3922490f69be83409868..cbf51ae81855bc5bc255a4aa3abb606cf93bce68 100644 (file)
@@ -17,6 +17,7 @@
  *
  * bit     23 - Input/Output (PXA2xx specific)
  * bit     24 - Wakeup Enable(PXA2xx specific)
+ * bit     25 - Keep Output  (PXA2xx specific)
  */
 
 #define MFP_DIR_IN             (0x0 << 23)
 #define MFP_DIR(x)             (((x) >> 23) & 0x1)
 
 #define MFP_LPM_CAN_WAKEUP     (0x1 << 24)
+
+/*
+ * MFP_LPM_KEEP_OUTPUT must be specified for pins that need to
+ * retain their last output level (low or high).
+ * Note: MFP_LPM_KEEP_OUTPUT has no effect on pins configured for input.
+ */
 #define MFP_LPM_KEEP_OUTPUT    (0x1 << 25)
 
 #define WAKEUP_ON_EDGE_RISE    (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_RISE)
index b0a842887780f9acbe32e4223b4fe769f49b88f1..d2373d79b657fa9d6cd59184a00a1e2ff432762c 100644 (file)
@@ -366,14 +366,22 @@ static int pxa2xx_mfp_suspend(void)
        }
 
        for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) {
-
                saved_gafr[0][i] = GAFR_L(i);
                saved_gafr[1][i] = GAFR_U(i);
                saved_gpdr[i] = GPDR(i * 32);
                saved_pgsr[i] = PGSR(i);
+       }
 
-               GPDR(i * 32) = gpdr_lpm[i];
+       /* set GPDR bits taking into account MFP_LPM_KEEP_OUTPUT */
+       for (i = 0; i < pxa_last_gpio; i++) {
+               if ((gpdr_lpm[gpio_to_bank(i)] & GPIO_bit(i)) ||
+                   ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) &&
+                    (saved_gpdr[gpio_to_bank(i)] & GPIO_bit(i))))
+                       GPDR(i) |= GPIO_bit(i);
+               else
+                       GPDR(i) &= ~GPIO_bit(i);
        }
+
        return 0;
 }