summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorDominic Chen <ddchen@chromium.org>2014-07-15 17:05:35 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-08-13 13:21:00 +0000
commitfe1981a414384e30b9e2a197f893c6b281b9d49a (patch)
tree5907b0271e66b5c7d526fe360b3f461c5f684941 /driver
parent283fe98939fa56c61280529e2f933bedb122a52a (diff)
downloadchrome-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.mk1
-rw-r--r--driver/pi3usb9281.h86
-rw-r--r--driver/usb_switch_pi3usb9281.c178
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);