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
116
117
118
119
120
121
|
/* 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.
*
* AMD FP5 USB/DP Mux.
*/
#include "amd_fp5.h"
#include "chipset.h"
#include "common.h"
#include "i2c.h"
#include "usb_mux.h"
static inline int amd_fp5_mux_read(const struct usb_mux *me, uint8_t *val)
{
uint8_t buf[3] = { 0 };
int rv;
rv = i2c_xfer(I2C_PORT_USB_MUX, AMD_FP5_MUX_I2C_ADDR_FLAGS,
NULL, 0, buf, 3);
if (rv)
return rv;
*val = buf[me->usb_port + 1];
return EC_SUCCESS;
}
static inline int amd_fp5_mux_write(const struct usb_mux *me, uint8_t val)
{
return i2c_write8(I2C_PORT_USB_MUX, AMD_FP5_MUX_I2C_ADDR_FLAGS,
me->usb_port, val);
}
static int amd_fp5_init(const struct usb_mux *me)
{
return EC_SUCCESS;
}
static int amd_fp5_set_mux(const struct usb_mux *me, mux_state_t mux_state)
{
uint8_t val = 0;
/*
* This MUX is on the FP5 SoC. If that device is not powered then
* we either have to complain that it is not powered or if we were
* setting the state to OFF, then go ahead and report that we did
* it because a powered down MUX is off.
*/
if (chipset_in_state(CHIPSET_STATE_HARD_OFF))
return (mux_state == USB_PD_MUX_NONE)
? EC_SUCCESS
: EC_ERROR_NOT_POWERED;
if ((mux_state & USB_PD_MUX_USB_ENABLED) &&
(mux_state & USB_PD_MUX_DP_ENABLED))
val = (mux_state & USB_PD_MUX_POLARITY_INVERTED)
? AMD_FP5_MUX_DOCK_INVERTED : AMD_FP5_MUX_DOCK;
else if (mux_state & USB_PD_MUX_USB_ENABLED)
val = (mux_state & USB_PD_MUX_POLARITY_INVERTED)
? AMD_FP5_MUX_USB_INVERTED : AMD_FP5_MUX_USB;
else if (mux_state & USB_PD_MUX_DP_ENABLED)
val = (mux_state & USB_PD_MUX_POLARITY_INVERTED)
? AMD_FP5_MUX_DP_INVERTED : AMD_FP5_MUX_DP;
return amd_fp5_mux_write(me, val);
}
static int amd_fp5_get_mux(const struct usb_mux *me, mux_state_t *mux_state)
{
uint8_t val = AMD_FP5_MUX_SAFE;
/*
* This MUX is on the FP5 SoC. Only access the device if we
* have power. If that device is not powered then claim the
* state to be NONE, which is SAFE.
*/
if (!chipset_in_state(CHIPSET_STATE_HARD_OFF)) {
int rv;
rv = amd_fp5_mux_read(me, &val);
if (rv)
return rv;
}
switch (val) {
case AMD_FP5_MUX_USB:
*mux_state = USB_PD_MUX_USB_ENABLED;
break;
case AMD_FP5_MUX_USB_INVERTED:
*mux_state = USB_PD_MUX_USB_ENABLED |
USB_PD_MUX_POLARITY_INVERTED;
break;
case AMD_FP5_MUX_DOCK:
*mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED;
break;
case AMD_FP5_MUX_DOCK_INVERTED:
*mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED
| USB_PD_MUX_POLARITY_INVERTED;
break;
case AMD_FP5_MUX_DP:
*mux_state = USB_PD_MUX_DP_ENABLED;
break;
case AMD_FP5_MUX_DP_INVERTED:
*mux_state = USB_PD_MUX_DP_ENABLED |
USB_PD_MUX_POLARITY_INVERTED;
break;
case AMD_FP5_MUX_SAFE:
default:
*mux_state = USB_PD_MUX_NONE;
break;
}
return EC_SUCCESS;
}
const struct usb_mux_driver amd_fp5_usb_mux_driver = {
.init = &amd_fp5_init,
.set = &amd_fp5_set_mux,
.get = &amd_fp5_get_mux,
};
|