diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-03-13 16:31:59 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2012-03-16 11:03:13 -0700 |
commit | a9f4794edb0a7db06b34bf344809db4393e679ac (patch) | |
tree | 02fbc4d9be296813b7f8ed2fb1993f2df2d4607a | |
parent | 54f8d7e323ce6e36612732b4d107e6ee846c6fad (diff) | |
download | chrome-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.c | 1 | ||||
-rw-r--r-- | board/link/board.h | 5 | ||||
-rw-r--r-- | chip/lm4/build.mk | 1 | ||||
-rw-r--r-- | chip/lm4/onewire.c | 140 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/main.c | 4 | ||||
-rw-r--r-- | common/power_led.c | 100 | ||||
-rw-r--r-- | include/onewire.h | 32 | ||||
-rw-r--r-- | include/power_led.h | 24 |
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 */ |