summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-11-29 10:51:08 -0800
committerRandall Spangler <rspangler@chromium.org>2012-11-29 12:02:51 -0800
commit52440ef89387809af91051671a98ea9c36ce27ca (patch)
tree068f68e055c37da2d945cbe4307959e0a8d04bb5
parent108754005d86c17b6247e83e2b7aed788d93a8c9 (diff)
downloadchrome-ec-52440ef89387809af91051671a98ea9c36ce27ca.tar.gz
link: Disable interrupts while reading/writing bits via onewire
When reading, the line must be sampled in a narrow timing window after the output pulse. Interrupts or context switches during this time corrupt the data. Similarly, when writing, the difference between a 0-bit and a 1-bit is the length of the output pulse. So a context switch or interrupt there can turn a 1-bit into a 0-bit. BUG=chrome-os-partner:15507 BRANCH=link TEST=manual 0. plug in AC power 1. hold down shift key for the duration of this test 2. powerled yellow 3. powerled red 4. repeat steps 2-3 several times 5. release shift key Power adapter LED should toggle color each time. (It may also toggle to the normally expected color during this experiment, if the charging task updates it.) Power adapter LED should NOT turn off during this test. Change-Id: Ief11e6e9a5b07aa3a25c60c50e4e7744a4705713 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/38925 Reviewed-by: Yung-Chieh Lo <yjlou@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/lm4/onewire.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/chip/lm4/onewire.c b/chip/lm4/onewire.c
index 082ce1238a..0c795eeedc 100644
--- a/chip/lm4/onewire.c
+++ b/chip/lm4/onewire.c
@@ -9,6 +9,7 @@
#include "gpio.h"
#include "hooks.h"
#include "registers.h"
+#include "task.h"
#include "timer.h"
#define ONEWIRE_PIN (1<<2) /* One-wire pin mask (on GPIO H) */
@@ -56,6 +57,12 @@ static int readbit(void)
{
int bit;
+ /*
+ * The delay between sending the output pulse and reading the bit is
+ * extremely timing sensitive, so disable interrupts.
+ */
+ interrupt_disable();
+
/* Output low */
output0(T_RL);
@@ -65,6 +72,13 @@ static int readbit(void)
/* Read bit */
bit = readline();
+ /*
+ * Enable interrupt as soon as we've read the bit. The delay to the
+ * end of the timeslot is a lower bound, so additional latency here is
+ * harmless.
+ */
+ interrupt_enable();
+
/* Delay to end of timeslot */
udelay(T_SLOT - T_MSR);
return bit;
@@ -75,13 +89,25 @@ static int readbit(void)
*/
static void writebit(int bit)
{
+ /*
+ * The delays in the output-low signal for sending 0 and 1 bits are
+ * extremely timing sensitive, so disable interrupts during that time.
+ * Interrupts can be enabled again as soon as the output is switched
+ * back to open-drain, since the delay for the rest of the timeslot is
+ * a lower bound.
+ */
if (bit) {
+ interrupt_disable();
output0(T_W1L);
+ interrupt_enable();
udelay(T_SLOT - T_W1L);
} else {
+ interrupt_disable();
output0(T_W0L);
+ interrupt_enable();
udelay(T_SLOT - T_W0L);
}
+
}
int onewire_reset(void)