1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
/* 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_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 < CONFIG_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,
};
|