mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
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>
This commit is contained in:
committed by
chrome-internal-fetch
parent
283fe98939
commit
fe1981a414
@@ -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
|
||||
|
||||
86
driver/pi3usb9281.h
Normal file
86
driver/pi3usb9281.h
Normal file
@@ -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 */
|
||||
178
driver/usb_switch_pi3usb9281.c
Normal file
178
driver/usb_switch_pi3usb9281.c
Normal file
@@ -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);
|
||||
@@ -968,6 +968,12 @@
|
||||
/* Support the TSU6721 I2C smart switch */
|
||||
#undef CONFIG_USB_SWITCH_TSU6721
|
||||
|
||||
/* Support the Pericom PI3USB9281 I2C USB switch */
|
||||
#undef CONFIG_USB_SWITCH_PI3USB9281
|
||||
|
||||
/* Select GPIO MUX for Pericom PI3USB9281 I2C USB switch */
|
||||
#undef CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Support computing hash of code for verified boot */
|
||||
|
||||
Reference in New Issue
Block a user