diff options
author | Dominic Chen <ddchen@chromium.org> | 2014-07-15 17:05:35 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-08-13 13:21:00 +0000 |
commit | fe1981a414384e30b9e2a197f893c6b281b9d49a (patch) | |
tree | 5907b0271e66b5c7d526fe360b3f461c5f684941 /driver | |
parent | 283fe98939fa56c61280529e2f933bedb122a52a (diff) | |
download | chrome-ec-fe1981a414384e30b9e2a197f893c6b281b9d49a.tar.gz |
pi3usb9281: Implement driver for Pericom USB switch
BRANCH=none
BUG=none
TEST=verify that usb switch funcitons
Change-Id: Ie897a2ae94042abefbb349d30dfa183caaec9ed0
Signed-off-by: Dominic Chen <ddchen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/209846
Reviewed-by: Vic Yang <victoryang@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/build.mk | 1 | ||||
-rw-r--r-- | driver/pi3usb9281.h | 86 | ||||
-rw-r--r-- | driver/usb_switch_pi3usb9281.c | 178 |
3 files changed, 265 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk index 74c4bb6e3f..d3872acf6e 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -44,4 +44,5 @@ driver-$(CONFIG_TEMP_SENSOR_TMP006)+=temp_sensor/tmp006.o driver-$(CONFIG_TEMP_SENSOR_TMP432)+=temp_sensor/tmp432.o # USB switches +driver-$(CONFIG_USB_SWITCH_PI3USB9281)+=usb_switch_pi3usb9281.o driver-$(CONFIG_USB_SWITCH_TSU6721)+=usb_switch_tsu6721.o diff --git a/driver/pi3usb9281.h b/driver/pi3usb9281.h new file mode 100644 index 0000000000..ebcd333d80 --- /dev/null +++ b/driver/pi3usb9281.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2014 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. + * + * Pericom PI3USB9281 USB port switch. + */ + +#ifndef PI3USB9281_H +#define PI3USB9281_H + +#define PI3USB9281_REG_DEV_ID 0x01 +#define PI3USB9281_REG_CONTROL 0x02 +#define PI3USB9281_REG_INT 0x03 +#define PI3USB9281_REG_INT_MASK 0x05 +#define PI3USB9281_REG_DEV_TYPE 0x0a +#define PI3USB9281_REG_CHG_STATUS 0x0e +#define PI3USB9281_REG_MANUAL 0x13 +#define PI3USB9281_REG_RESET 0x1b +#define PI3USB9281_REG_VBUS 0x1d + +#define PI3USB9281_CTRL_INT_MASK (1 << 0) +#define PI3USB9281_CTRL_AUTO (1 << 2) +#define PI3USB9281_CTRL_SWITCH_AUTO (1 << 4) + +#define PI3USB9281_PIN_MANUAL_VBUS (3 << 0) +#define PI3USB9281_PIN_MANUAL_DP (1 << 2) +#define PI3USB9281_PIN_MANUAL_DM (1 << 5) + +#define PI3USB9281_INT_ATTACH (1 << 0) +#define PI3USB9281_INT_DETACH (1 << 1) +#define PI3USB9281_INT_OVP (1 << 5) +#define PI3USB9281_INT_OCP (1 << 6) +#define PI3USB9281_INT_OVP_OC (1 << 7) + +#define PI3USB9281_TYPE_NONE 0 +#define PI3USB9281_TYPE_MHL (1 << 0) +#define PI3USB9281_TYPE_OTG (1 << 1) +#define PI3USB9281_TYPE_SDP (1 << 2) +#define PI3USB9281_TYPE_CAR (1 << 4) +#define PI3USB9281_TYPE_CDP (1 << 5) +#define PI3USB9281_TYPE_DCP (1 << 6) + +#define PI3USB9281_CHG_NONE 0 +#define PI3USB9281_CHG_CAR_TYPE1 (1 << 1) +#define PI3USB9281_CHG_CAR_TYPE2 (3 << 0) +#define PI3USB9281_CHG_APPLE_1A (1 << 2) +#define PI3USB9281_CHG_APPLE_2A (1 << 3) +#define PI3USB9281_CHG_APPLE_2_4A (1 << 4) + +/* Read PI3USB9281 register. */ +uint8_t pi3usb9281_read(uint8_t chip_idx, uint8_t reg); + +/* Write PI3USB9281 register. */ +int pi3usb9281_write(uint8_t chip_idx, uint8_t reg, uint8_t val); + +/* Enable interrupts. */ +int pi3usb9281_enable_interrupts(uint8_t chip_idx); + +/* Disable all interrupts. */ +int pi3usb9281_disable_interrupts(uint8_t chip_idx); + +/* Set interrupt mask. */ +int pi3usb9281_set_interrupt_mask(uint8_t chip_idx, uint8_t mask); + +/* Get and clear current interrupt status. */ +int pi3usb9281_get_interrupts(uint8_t chip_idx); + +/* Get but keep interrupt status. */ +int pi3usb9281_peek_interrupts(uint8_t chip_idx); + +/* Get attached device type. */ +int pi3usb9281_get_device_type(uint8_t chip_idx); + +/* Get attached charger status. */ +int pi3usb9281_get_charger_status(uint8_t chip_idx); + +/* Set switch configuration to manual. */ +int pi3usb9281_set_switch_manual(uint8_t chip_idx, int val); + +/* Set bits to enable pins in manual switch register */ +int pi3usb9281_set_pins(uint8_t chip_idx, uint8_t mask); + +/* Reset PI3USB9281. */ +int pi3usb9281_reset(uint8_t chip_idx); + +#endif /* PI3USB9281_H */ diff --git a/driver/usb_switch_pi3usb9281.c b/driver/usb_switch_pi3usb9281.c new file mode 100644 index 0000000000..b7a82a2e09 --- /dev/null +++ b/driver/usb_switch_pi3usb9281.c @@ -0,0 +1,178 @@ +/* Copyright (c) 2014 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. + * + * Pericom PI3USB3281 USB port switch driver. + */ + +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "i2c.h" +#include "timer.h" +#include "pi3usb9281.h" +#include "util.h" + + /* Console output macros */ +#define CPUTS(outstr) cputs(CC_USBCHARGE, outstr) +#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) + +/* 8-bit I2C address */ +#define PI3USB9281_I2C_ADDR (0x25 << 1) + +/* Delay values */ +#define PI3USB9281_SW_RESET_DELAY 20 + +#ifdef CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO +#define PI3USB9281_COUNT 2 +static inline void select_chip(uint8_t chip_idx) +{ + gpio_set_level(CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO, chip_idx); +} +#else +#define PI3USB9281_COUNT 1 +#define select_chip(x) +#endif + +static int saved_interrupts[PI3USB9281_COUNT]; + +uint8_t pi3usb9281_read(uint8_t chip_idx, uint8_t reg) +{ + int res, val; + + select_chip(chip_idx); + res = i2c_read8(I2C_PORT_MASTER, PI3USB9281_I2C_ADDR, reg, &val); + if (res) + return 0xee; + + return val; +} + +int pi3usb9281_write(uint8_t chip_idx, uint8_t reg, uint8_t val) +{ + int res; + + select_chip(chip_idx); + res = i2c_write8(I2C_PORT_MASTER, PI3USB9281_I2C_ADDR, reg, val); + if (res) + CPRINTS("PI3USB9281 I2C write failed"); + return res; +} + +int pi3usb9281_enable_interrupts(uint8_t chip_idx) +{ + int ctrl = pi3usb9281_read(chip_idx, PI3USB9281_REG_CONTROL); + + if (ctrl == 0xee) + return EC_ERROR_UNKNOWN; + + return pi3usb9281_write(chip_idx, PI3USB9281_REG_CONTROL, ctrl & 0x14); +} + +int pi3usb9281_disable_interrupts(uint8_t chip_idx) +{ + int ctrl = pi3usb9281_read(chip_idx, PI3USB9281_REG_CONTROL); + int rv; + + if (ctrl == 0xee) + return EC_ERROR_UNKNOWN; + + rv = pi3usb9281_write(chip_idx, PI3USB9281_REG_CONTROL, + (ctrl | PI3USB9281_CTRL_INT_MASK) & 0x15); + pi3usb9281_get_interrupts(chip_idx); + return rv; +} + +int pi3usb9281_set_interrupt_mask(uint8_t chip_idx, uint8_t mask) +{ + return pi3usb9281_write(chip_idx, PI3USB9281_REG_INT_MASK, ~mask); +} + +int pi3usb9281_get_interrupts(uint8_t chip_idx) +{ + int ret = pi3usb9281_peek_interrupts(chip_idx); + + if (chip_idx >= PI3USB9281_COUNT) + return EC_ERROR_PARAM1; + + saved_interrupts[chip_idx] = 0; + return ret; +} + +int pi3usb9281_peek_interrupts(uint8_t chip_idx) +{ + if (chip_idx >= PI3USB9281_COUNT) + return EC_ERROR_PARAM1; + + saved_interrupts[chip_idx] |= pi3usb9281_read(chip_idx, + PI3USB9281_REG_INT); + return saved_interrupts[chip_idx]; +} + +int pi3usb9281_get_device_type(uint8_t chip_idx) +{ + return pi3usb9281_read(chip_idx, PI3USB9281_REG_DEV_TYPE) & 0x77; +} + +int pi3usb9281_get_charger_status(uint8_t chip_idx) +{ + return pi3usb9281_read(chip_idx, PI3USB9281_REG_CHG_STATUS) & 0x1f; +} + +int pi3usb9281_get_vbus(uint8_t chip_idx) +{ + int vbus = pi3usb9281_read(chip_idx, PI3USB9281_REG_VBUS); + if (vbus == 0xee) + return EC_ERROR_UNKNOWN; + + return !!(vbus & 0x2); +} + +int pi3usb9281_reset(uint8_t chip_idx) +{ + int rv = pi3usb9281_write(chip_idx, PI3USB9281_REG_RESET, 0x1); + + if (!rv) + /* Reset takes ~15ms. Wait for 20ms to be safe. */ + msleep(PI3USB9281_SW_RESET_DELAY); + + return rv; +} + +int pi3usb9281_set_switch_manual(uint8_t chip_idx, int val) +{ + int ctrl; + int rv; + + ctrl = pi3usb9281_read(chip_idx, PI3USB9281_REG_CONTROL); + if (ctrl == 0xee) + return EC_ERROR_UNKNOWN; + + if (val) + rv = pi3usb9281_write(chip_idx, PI3USB9281_REG_CONTROL, + ctrl & ~PI3USB9281_CTRL_AUTO); + else + rv = pi3usb9281_write(chip_idx, PI3USB9281_REG_CONTROL, + ctrl | PI3USB9281_CTRL_AUTO); + + return rv; +} + +int pi3usb9281_set_pins(uint8_t chip_idx, uint8_t val) +{ + return pi3usb9281_write(chip_idx, PI3USB9281_REG_MANUAL, val); +} + +static void pi3usb9281_init(void) +{ + uint8_t dev_id; + int i; + + for (i = 0; i < PI3USB9281_COUNT; i++) { + dev_id = pi3usb9281_read(i, PI3USB9281_REG_DEV_ID); + + if (dev_id != 0x10) + CPRINTS("PI3USB9281[%d] invalid ID 0x%02x", i, dev_id); + } +} +DECLARE_HOOK(HOOK_INIT, pi3usb9281_init, HOOK_PRIO_LAST); |