/* Copyright 2019 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. */ /* * AOZ1380 USB-C Power Path Controller * * This is a basic TCPM controlled PPC driver. It could easily be * renamed and repurposed to be generic, if there are other TCPM * controlled PPC chips that are similar to the AOZ1380 */ #include "common.h" #include "console.h" #include "driver/ppc/aoz1380.h" #include "hooks.h" #include "system.h" #include "tcpm.h" #include "usb_pd.h" #include "usb_pd_tcpc.h" #include "usbc_ppc.h" #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */ #define AOZ1380_FLAGS_SOURCE_ENABLED BIT(0) static uint8_t flags[CONFIG_USB_PD_PORT_MAX_COUNT]; static int aoz1380_init(int port) { flags[port] = 0; return EC_SUCCESS; } static int aoz1380_vbus_sink_enable(int port, int enable) { int rv; rv = tcpm_set_snk_ctrl(port, enable); return rv; } static int aoz1380_vbus_source_enable(int port, int enable) { int rv; rv = tcpm_set_src_ctrl(port, enable); if (rv) return rv; if (enable) flags[port] |= AOZ1380_FLAGS_SOURCE_ENABLED; else flags[port] &= ~AOZ1380_FLAGS_SOURCE_ENABLED; return rv; } static int aoz1380_is_sourcing_vbus(int port) { return flags[port] & AOZ1380_FLAGS_SOURCE_ENABLED; } static int aoz1380_set_vbus_source_current_limit(int port, enum tcpc_rp_value rp) { return board_aoz1380_set_vbus_source_current_limit(port, rp); } /* * AOZ1380 Interrupt Handler * * This device only has a single over current/temperature interrupt. * TODO(b/141939343) Determine how to clear the interrupt * TODO(b/142076004) Test this to verify we shut off vbus current */ static void aoz1380_handle_interrupt(int port) { /* * This is a over current/temperature condition */ CPRINTS("C%d: PPC detected Vbus overcurrent/temperature!", port); pd_handle_overcurrent(port); } static void aoz1380_irq_deferred(void) { int i; uint32_t pending = atomic_read_clear(&irq_pending); for (i = 0; i < board_get_usb_pd_port_count(); i++) if (BIT(i) & pending) aoz1380_handle_interrupt(i); } DECLARE_DEFERRED(aoz1380_irq_deferred); void aoz1380_interrupt(int port) { atomic_or(&irq_pending, BIT(port)); hook_call_deferred(&aoz1380_irq_deferred_data, 0); } const struct ppc_drv aoz1380_drv = { .init = &aoz1380_init, .is_sourcing_vbus = &aoz1380_is_sourcing_vbus, .vbus_sink_enable = &aoz1380_vbus_sink_enable, .vbus_source_enable = &aoz1380_vbus_source_enable, .set_vbus_source_current_limit = &aoz1380_set_vbus_source_current_limit, };