summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-03-13 16:31:59 -0700
committerRandall Spangler <rspangler@chromium.org>2012-03-16 11:03:13 -0700
commita9f4794edb0a7db06b34bf344809db4393e679ac (patch)
tree02fbc4d9be296813b7f8ed2fb1993f2df2d4607a
parent54f8d7e323ce6e36612732b4d107e6ee846c6fad (diff)
downloadchrome-ec-a9f4794edb0a7db06b34bf344809db4393e679ac.tar.gz
Add support for 1-wire protocol and power adapter LEDs
BUG=chrome-os-partner:7498 TEST=powerled {off, red, yellow, green} Signed-off-by: Randall Spangler <rspangler@chromium.org> Change-Id: I48beaad94d75c0ec30a969ea4b0e35f54e052085
-rw-r--r--board/link/board.c1
-rw-r--r--board/link/board.h5
-rw-r--r--chip/lm4/build.mk1
-rw-r--r--chip/lm4/onewire.c140
-rw-r--r--common/build.mk1
-rw-r--r--common/main.c4
-rw-r--r--common/power_led.c100
-rw-r--r--include/onewire.h32
-rw-r--r--include/power_led.h24
9 files changed, 305 insertions, 3 deletions
diff --git a/board/link/board.c b/board/link/board.c
index 3fc24a3086..e6a03a0228 100644
--- a/board/link/board.c
+++ b/board/link/board.c
@@ -30,7 +30,6 @@ const struct gpio_info gpio_list[GPIO_COUNT] = {
{"LID_SWITCHn", LM4_GPIO_K, (1<<5), GPIO_INT_BOTH,
power_button_interrupt},
/* Other inputs */
- {"POWER_ONEWIRE", LM4_GPIO_H, (1<<2), 0, NULL},
{"THERMAL_DATA_READYn", LM4_GPIO_B, (1<<4), 0, NULL},
{"AC_PRESENT", LM4_GPIO_H, (1<<3), 0, NULL},
{"PCH_BKLTEN", LM4_GPIO_J, (1<<3), GPIO_INT_BOTH,
diff --git a/board/link/board.h b/board/link/board.h
index d09d45f030..26f21477ea 100644
--- a/board/link/board.h
+++ b/board/link/board.h
@@ -9,9 +9,11 @@
#define __BOARD_H
/* Optional features */
+#define CONFIG_ONEWIRE
#define CONFIG_PECI
-#define CONFIG_TMP006
+#define CONFIG_POWER_LED
#define CONFIG_PSTORE
+#define CONFIG_TMP006
/* 66.667 Mhz clock frequency */
#define CPU_CLOCK 66666667
@@ -110,7 +112,6 @@ enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */
GPIO_POWER_BUTTONn = 0, /* Power button */
GPIO_LID_SWITCHn, /* Lid switch */
- GPIO_POWER_ONEWIRE, /* 1-wire interface to power adapter LEDs */
GPIO_THERMAL_DATA_READYn, /* Data ready from I2C thermal sensor */
/* Other inputs */
GPIO_AC_PRESENT, /* AC power present */
diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk
index e1ef913631..df9b425c58 100644
--- a/chip/lm4/build.mk
+++ b/chip/lm4/build.mk
@@ -13,6 +13,7 @@ chip-y+=clock.o gpio.o system.o uart.o
chip-y+=watchdog.o eeprom.o hwtimer.o
chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_LPC)+=lpc.o
+chip-$(CONFIG_ONEWIRE)+=onewire.o
chip-$(CONFIG_PECI)+=peci.o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_TEMP_SENSOR)+=chip_temp_sensor.o
diff --git a/chip/lm4/onewire.c b/chip/lm4/onewire.c
new file mode 100644
index 0000000000..3cfb7c7401
--- /dev/null
+++ b/chip/lm4/onewire.c
@@ -0,0 +1,140 @@
+/* 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 "board.h"
+#include "gpio.h"
+#include "timer.h"
+#include "registers.h"
+
+#define ONEWIRE_PIN (1<<2) /* One-wire pin mask (on GPIO 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)
+{
+ LM4_GPIO_DIR(LM4_GPIO_H) |= ONEWIRE_PIN;
+ LM4_GPIO_DATA(LM4_GPIO_H, ONEWIRE_PIN) = 0;
+ udelay(usec);
+ LM4_GPIO_DIR(LM4_GPIO_H) &= ~ONEWIRE_PIN;
+}
+
+
+/* Read the signal line */
+static int readline(void)
+{
+ return LM4_GPIO_DATA(LM4_GPIO_H, ONEWIRE_PIN) ? 1 : 0;
+}
+
+
+/* Read a bit */
+static int readbit(void)
+{
+ int bit;
+
+ /* 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 = readline();
+
+ /* Delay to end of timeslot */
+ udelay(T_SLOT - T_MSR);
+ return bit;
+}
+
+
+/* Write a bit */
+static void writebit(int bit)
+{
+ if (bit) {
+ output0(T_W1L);
+ udelay(T_SLOT - T_W1L);
+ } else {
+ output0(T_W0L);
+ udelay(T_SLOT - T_W0L);
+ }
+}
+
+
+int onewire_reset(void)
+{
+ /* Start transaction with master reset pulse */
+ output0(T_RSTL);
+
+ /* Wait for presence detect sample time */
+ udelay(T_MSP);
+ /* 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. */
+ if (readline() != 0)
+ 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 */
+}
+
+/*****************************************************************************/
+/* Initialization */
+
+/* Configures GPIOs for the module. */
+static void configure_gpio(void)
+{
+ /* Configure 1-wire pin as open-drain GPIO */
+ gpio_set_alternate_function(LM4_GPIO_H, ONEWIRE_PIN, 0);
+ LM4_GPIO_ODR(LM4_GPIO_H) |= ONEWIRE_PIN;
+}
+
+
+int onewire_init(void)
+{
+ /* Configure GPIOs */
+ configure_gpio();
+
+ return EC_SUCCESS;
+}
diff --git a/common/build.mk b/common/build.mk
index a30288d383..3c371c2078 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -20,6 +20,7 @@ common-$(CONFIG_TASK_THERMAL)+=thermal.o thermal_commands.o
common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o temp_sensor_commands.o
common-$(CONFIG_TMP006)+=tmp006.o
common-$(CONFIG_LIGHTBAR)+=leds.o
+common-$(CONFIG_POWER_LED)+=power_led.o
# Board driver modules
common-$(CONFIG_CHARGER_BQ24725)+=charger_bq24725.o
diff --git a/common/main.c b/common/main.c
index 64b044ce75..ca9426ee55 100644
--- a/common/main.c
+++ b/common/main.c
@@ -20,6 +20,7 @@
#include "keyboard_scan.h"
#include "lpc.h"
#include "memory_commands.h"
+#include "onewire.h"
#include "peci.h"
#include "port80.h"
#include "power_button.h"
@@ -93,6 +94,9 @@ int main(void)
#endif
adc_init();
usb_charge_init();
+#ifdef CONFIG_ONEWIRE
+ onewire_init();
+#endif
#ifdef CONFIG_CHARGER
charger_init();
#endif
diff --git a/common/power_led.c b/common/power_led.c
new file mode 100644
index 0000000000..b90c72ae95
--- /dev/null
+++ b/common/power_led.c
@@ -0,0 +1,100 @@
+/* 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.
+ */
+
+/* Power LED control for Chrome EC */
+
+#include "console.h"
+#include "onewire.h"
+#include "power_led.h"
+#include "timer.h"
+#include "uart.h"
+#include "util.h"
+
+#define POWERLED_RETRIES 10
+
+static const uint8_t led_masks[POWERLED_COLOR_COUNT] = {0xff, 0xfe, 0xfc, 0xfd};
+static const char * const color_names[POWERLED_COLOR_COUNT] = {
+ "off", "red", "yellow", "green"};
+
+
+/* Set the power LED GPIO controller outputs to the specified mask. */
+static int powerled_set_mask(int mask)
+{
+ int rv;
+
+ /* Reset the 1-wire bus */
+ rv = onewire_reset();
+ if (rv)
+ return rv;
+
+ /* Skip ROM, since only one device */
+ onewire_write(0xcc);
+
+ /* Write and turn on the LEDs */
+ onewire_write(0x5a);
+ onewire_write(mask);
+ onewire_write(~mask); /* Repeat inverted */
+
+ rv = onewire_read(); /* Confirmation byte */
+ if (rv != 0xaa)
+ return EC_ERROR_UNKNOWN;
+
+ /* The next byte is a read-back of the chip status. Since we're only
+ * using lines as outputs, we can ignore it. */
+ return EC_SUCCESS;
+}
+
+
+int powerled_set(enum powerled_color color)
+{
+ int rv = EC_SUCCESS;
+ int i;
+
+ /* 1-wire communication can fail for timing reasons in the current
+ * system. We have a limited timing window to send/receive bits, but
+ * we can't disable interrupts for the rest of the system to guarantee
+ * we hit that window. Instead, simply retry the low-level command a
+ * few times. */
+ for (i = 0; i < POWERLED_RETRIES; i++) {
+ rv = powerled_set_mask(led_masks[color]);
+ if (rv == EC_SUCCESS)
+ break;
+
+ /* Sleep for a bit between tries. This gives the 1-wire GPIO
+ * chip time to recover from the failed attempt, and allows
+ * lower-priority tasks a chance to run. */
+ usleep(100);
+ }
+
+ return rv;
+}
+
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_powerled(int argc, char **argv)
+{
+ int i = POWERLED_COLOR_COUNT;
+
+ /* Pick a color, any color... */
+ if (argc >= 1) {
+ for (i = 0; i < POWERLED_COLOR_COUNT; i++) {
+ if (!strcasecmp(argv[1], color_names[i]))
+ break;
+ }
+ }
+ if (i >= POWERLED_COLOR_COUNT) {
+ uart_puts("Please specify a color:");
+ for (i = 0; i < POWERLED_COLOR_COUNT; i++)
+ uart_printf(" %s", color_names[i]);
+ uart_puts("\n");
+ return EC_ERROR_INVAL;
+ }
+
+ uart_printf("Setting power LED to %s...\n", color_names[i]);
+ return powerled_set(i);
+}
+DECLARE_CONSOLE_COMMAND(powerled, command_powerled);
diff --git a/include/onewire.h b/include/onewire.h
new file mode 100644
index 0000000000..b7120dca90
--- /dev/null
+++ b/include/onewire.h
@@ -0,0 +1,32 @@
+/* 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 for Chrome EC */
+
+/* Note that 1-wire communication is VERY latency-sensitive. If these
+ * functions are run at low priority, communication may be garbled. However,
+ * these functions are also slow enough (~1ms per call) that it's really not
+ * desirable to put them at high priority. So make sure you check the
+ * confirmation code from the slave for any communication, and retry a few
+ * times in case of failure. */
+
+#ifndef __CROS_EC_ONEWIRE_H
+#define __CROS_EC_ONEWIRE_H
+
+#include "common.h"
+
+/* Initialize the module. */
+int onewire_init(void);
+
+/* Reset the 1-wire bus. Returns error if presence detect fails. */
+int onewire_reset(void);
+
+/* Read a byte from the 1-wire bus. Returns the byte. */
+int onewire_read(void);
+
+/* Write a byte to the 1-wire bus. */
+void onewire_write(int data);
+
+#endif /* __CROS_EC_ONEWIRE_H */
diff --git a/include/power_led.h b/include/power_led.h
new file mode 100644
index 0000000000..9c8fa49f86
--- /dev/null
+++ b/include/power_led.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2011 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.
+ */
+
+/* Power LED control for Chrome EC */
+
+#ifndef __CROS_EC_POWER_LED_H
+#define __CROS_EC_POWER_LED_H
+
+#include "common.h"
+
+enum powerled_color {
+ POWERLED_OFF = 0,
+ POWERLED_RED,
+ POWERLED_YELLOW,
+ POWERLED_GREEN,
+ POWERLED_COLOR_COUNT /* Number of colors, not a color itself */
+};
+
+/* Set the power adapter LED to the specified color. */
+int powerled_set(enum powerled_color color);
+
+#endif /* __CROS_EC_POWER_LED_H */