summaryrefslogtreecommitdiff
path: root/include/usb_mux.h
blob: e4839547331828841bc5925f73c9b7c224b18542 (plain)
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* Copyright (c) 2012 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.
 */

/* USB mux driver */

#ifndef __CROS_EC_USB_MUX_H
#define __CROS_EC_USB_MUX_H

#include "ec_commands.h"
#include "tcpm.h"
#include "usb_charge.h"
#include "usb_pd.h"

/*
 * USB-C mux state
 *
 * A bitwise combination of the USB_PD_MUX_* flags.
 * The bottom 2 bits also correspond to the typec_mux enum type.
 */
typedef uint8_t mux_state_t;

/*
 * Packing and Unpacking defines used with USB_MUX_FLAG_NOT_TCPC
 * MUX_PORT takes in a USB-C port number and returns the I2C port number
 */
#define MUX_PORT_AND_ADDR(port, addr) ((port << 8) | (addr & 0xFF))
#define MUX_PORT(port) (usb_muxes[port].port_addr >> 8)
#define MUX_ADDR(port) (usb_muxes[port].port_addr & 0xFF)

/* Mux state attributes */
/* TODO: Directly use USB_PD_MUX_* everywhere and remove these 3 defines */
#define MUX_USB_ENABLED        USB_PD_MUX_USB_ENABLED
#define MUX_DP_ENABLED         USB_PD_MUX_DP_ENABLED
#define MUX_POLARITY_INVERTED  USB_PD_MUX_POLARITY_INVERTED

/* Mux modes, decoded to attributes */
enum typec_mux {
	TYPEC_MUX_NONE = 0,                /* Open switch */
	TYPEC_MUX_USB  = MUX_USB_ENABLED,  /* USB only */
	TYPEC_MUX_DP   = MUX_DP_ENABLED,   /* DP only */
	TYPEC_MUX_DOCK = MUX_USB_ENABLED | /* Both USB and DP */
			 MUX_DP_ENABLED,
};

/* Mux driver function pointers */
struct usb_mux_driver {
	/**
	 * Initialize USB mux. This is called every time the MUX is access after
	 * being put in a fully disconnected state (low power mode).
	 *
	 * @param port usb port of mux (not port_addr)
	 * @return EC_SUCCESS on success, non-zero error code on failure.
	 */
	int (*init)(int port);

	/**
	 * Set USB mux state.
	 *
	 * @param port usb port of mux (not port_addr)
	 * @param mux_state State to set mux to.
	 * @return EC_SUCCESS on success, non-zero error code on failure.
	 */
	int (*set)(int port, mux_state_t mux_state);

	/**
	 * Get current state of USB mux.
	 *
	 * @param port usb port of mux (not port_addr)
	 * @param mux_state Gets set to current state of mux.
	 * @return EC_SUCCESS on success, non-zero error code on failure.
	 */
	int (*get)(int port, mux_state_t *mux_state);

	/**
	 * Optional method that is called after the mux fully disconnects.
	 *
	 * Note: this method does not need to be defined for TCPC/MUX combos
	 * where the TCPC is actively used since the PD state machine
	 * will put the chip into lower power mode.
	 *
	 * @param port usb port of mux (not port_addr)
	 * @return EC_SUCCESS on success, non-zero error code on failure.
	 */
	int (*enter_low_power_mode)(int port);
};

/* Flags used for usb_mux.flags */
#define USB_MUX_FLAG_NOT_TCPC (1 << 0) /* TCPC/MUX device used only as MUX */

/* Describes a USB mux present in the system */
struct usb_mux {
	/*
	 * Used by driver. Muxes that are also the TCPC do not need to specify
	 * anything for this as they will use the values from tcpc_config_t. If
	 * this mux is also a TCPC but not used as the TCPC then use the
	 * MUX_PORT_AND_ADDR to pack the i2c port and i2c address into this
	 * field and use the USB_MUX_FLAG_NOT_TCPC flag.
	 */
	const int port_addr;

	/* Run-time flags with prefix USB_MUX_FLAG_ */
	const uint32_t flags;

	/* Mux driver */
	const struct usb_mux_driver *driver;

	/**
	 * Optional method for tuning for USB mux during mux->driver->init().
	 *
	 * @param port usb port of mux (not port_addr)
	 * @return EC_SUCCESS on success, non-zero error code on failure.
	 */
	int (*board_init)(int port);

	/*
	 * USB Type-C DP alt mode support. Notify Type-C controller
	 * there is DP dongle hot-plug.
	 * TODO: Move this function to usb_mux_driver struct.
	 */
	void (*hpd_update)(int port, int hpd_lvl, int hpd_irq);
};

/* Supported USB mux drivers */
extern const struct usb_mux_driver it5205_usb_mux_driver;
extern const struct usb_mux_driver pi3usb30532_usb_mux_driver;
extern const struct usb_mux_driver ps874x_usb_mux_driver;
extern const struct usb_mux_driver tcpm_usb_mux_driver;
extern const struct usb_mux_driver virtual_usb_mux_driver;

/* Supported hpd_update functions */
void virtual_hpd_update(int port, int hpd_lvl, int hpd_irq);

/* USB muxes present in system, ordered by PD port #, defined at board-level */
extern struct usb_mux usb_muxes[];

/*
 * Helper methods that either use tcpc communication or direct i2c
 * communication depending on how the TCPC/MUX device is configured.
 */
#ifdef CONFIG_USB_PD_TCPM_MUX
static inline int mux_write(int port, int reg, int val)
{
	return usb_muxes[port].flags & USB_MUX_FLAG_NOT_TCPC
		       ? i2c_write8(MUX_PORT(port), MUX_ADDR(port), reg, val)
		       : tcpc_write(port, reg, val);
}

static inline int mux_read(int port, int reg, int *val)
{
	return usb_muxes[port].flags & USB_MUX_FLAG_NOT_TCPC
		       ? i2c_read8(MUX_PORT(port), MUX_ADDR(port), reg, val)
		       : tcpc_read(port, reg, val);
}

static inline int mux_write16(int port, int reg, int val)
{
	return usb_muxes[port].flags & USB_MUX_FLAG_NOT_TCPC
		       ? i2c_write16(MUX_PORT(port), MUX_ADDR(port), reg, val)
		       : tcpc_write16(port, reg, val);
}

static inline int mux_read16(int port, int reg, int *val)
{
	return usb_muxes[port].flags & USB_MUX_FLAG_NOT_TCPC
		       ? i2c_read16(MUX_PORT(port), MUX_ADDR(port), reg, val)
		       : tcpc_read16(port, reg, val);
}
#endif /* CONFIG_USB_PD_TCPM_MUX */

/**
 * Initialize USB mux to its default state.
 *
 * @param port Port number.
 */
void usb_mux_init(int port);

/**
 * Configure superspeed muxes on type-C port.
 *
 * @param port port number.
 * @param mux_mode mux selected function.
 * @param usb_config usb2.0 selected function.
 * @param polarity plug polarity (0=CC1, 1=CC2).
 */
void usb_mux_set(int port, enum typec_mux mux_mode,
		 enum usb_switch usb_config, int polarity);

/**
 * Query superspeed mux status on type-C port.
 *
 * @param port port number.
 * @param dp_str pointer to the DP string to return.
 * @param usb_str pointer to the USB string to return.
 * @return Non-zero if superspeed connection is enabled; otherwise, zero.
 */
int usb_mux_get(int port, const char **dp_str, const char **usb_str);

/**
 * Flip the superspeed muxes on type-C port.
 *
 * This is used for factory test automation. Note that this function should
 * only flip the superspeed muxes and leave CC lines alone. Without further
 * changes, this function MUST ONLY be used for testing purpose, because
 * the protocol layer loses track of the superspeed polarity and DP/USB3.0
 * connection may break.
 *
 * @param port port number.
 */
void usb_mux_flip(int port);
#endif