summaryrefslogtreecommitdiff
path: root/common/onewire.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/onewire.c')
-rw-r--r--common/onewire.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/common/onewire.c b/common/onewire.c
new file mode 100644
index 0000000000..e57d6db5a1
--- /dev/null
+++ b/common/onewire.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* 1-wire interface module for Chrome EC */
+
+#include "common.h"
+#include "gpio.h"
+#include "task.h"
+#include "timer.h"
+
+/*
+ * Standard speed; all timings padded by 2 usec for safety.
+ *
+ * Note that these timing are actually _longer_ than legacy 1-wire standard
+ * speed because we're running the 1-wire bus at 3.3V instead of 5V.
+ */
+#define T_RSTL 602 /* Reset low pulse; 600-960 us */
+#define T_MSP 72 /* Presence detect sample time; 70-75 us */
+#define T_RSTH (68 + 260 + 5 + 2) /* Reset high; tPDHmax + tPDLmax + tRECmin */
+#define T_SLOT 70 /* Timeslot; >67 us */
+#define T_W0L 63 /* Write 0 low; 62-120 us */
+#define T_W1L 7 /* Write 1 low; 5-15 us */
+#define T_RL 7 /* Read low; 5-15 us */
+#define T_MSR 9 /* Read sample time; <15 us. Must be at least 200 ns after
+ * T_RL since that's how long the signal takes to be pulled
+ * up on our board. */
+
+/**
+ * Output low on the bus for <usec> us, then switch back to open-drain input.
+ */
+static void output0(int usec)
+{
+ gpio_set_flags(GPIO_ONEWIRE,
+ GPIO_OPEN_DRAIN | GPIO_OUTPUT | GPIO_OUT_LOW);
+ udelay(usec);
+ gpio_set_flags(GPIO_ONEWIRE, GPIO_INPUT);
+}
+
+/**
+ * Read a bit.
+ */
+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);
+
+ /* Delay to let slave release the line if it wants to send a 1-bit */
+ udelay(T_MSR - T_RL);
+
+ /* Read bit */
+ bit = gpio_get_level(GPIO_ONEWIRE);
+
+ /*
+ * 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;
+}
+
+/**
+ * Write a bit.
+ */
+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)
+{
+ /* Start transaction with master reset pulse */
+ output0(T_RSTL);
+
+ /* Wait for presence detect sample time.
+ *
+ * (Alternately, we could poll waiting for a 1-bit indicating our pulse
+ * has let go, then poll up to max time waiting for a 0-bit indicating
+ * the slave has responded.)
+ */
+ udelay(T_MSP);
+
+ if (gpio_get_level(GPIO_ONEWIRE))
+ return EC_ERROR_UNKNOWN;
+
+ /*
+ * Wait for end of presence pulse.
+ *
+ * (Alternately, we could poll waiting for a 1-bit.)
+ */
+ udelay(T_RSTH - T_MSP);
+
+ return EC_SUCCESS;
+}
+
+int onewire_read(void)
+{
+ int data = 0;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ data |= readbit() << i; /* LSB first */
+
+ return data;
+}
+
+void onewire_write(int data)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ writebit((data >> i) & 0x01); /* LSB first */
+}