summaryrefslogtreecommitdiff
path: root/driver/retimer/tusb544.c
blob: c2d617c3bed6c30b40bc656196757385df887435 (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
/* Copyright 2020 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * TI TUSB544 USB Type-C Multi-Protocol Linear Redriver
 */
#include "i2c.h"
#include "tusb544.h"
#include "usb_mux.h"

static int tusb544_write(const struct usb_mux *me, int offset, int data)
{
	return i2c_write8(me->i2c_port, me->i2c_addr_flags, offset, data);
}

static int tusb544_read(const struct usb_mux *me, int offset, int *data)
{
	return i2c_read8(me->i2c_port, me->i2c_addr_flags, offset, data);
}

int tusb544_i2c_field_update8(const struct usb_mux *me, int offset,
			      uint8_t field_mask, uint8_t set_value)
{
	int rv;

	rv = i2c_field_update8(me->i2c_port, me->i2c_addr_flags, offset,
			       field_mask, set_value);

	return rv;
}

static int tusb544_enter_low_power_mode(const struct usb_mux *me)
{
	int reg;
	int rv;

	rv = tusb544_read(me, TUSB544_REG_GENERAL4, &reg);
	if (rv)
		return rv;

	/* Setting CTL_SEL[0,1] to 0 powers down, per Table 5 */
	reg &= ~TUSB544_GEN4_CTL_SEL;
	/* Clear HPD */
	reg &= ~TUSB544_GEN4_HPDIN;

	return tusb544_write(me, TUSB544_REG_GENERAL4, reg);
}

static int tusb544_init(const struct usb_mux *me)
{
	return EC_SUCCESS;
}

static int tusb544_set_mux(const struct usb_mux *me, mux_state_t mux_state,
			   bool *ack_required)
{
	int reg;
	int rv;

	/* This driver does not use host command ACKs */
	*ack_required = false;

	/* This driver treats safe mode as none */
	if (mux_state == USB_PD_MUX_SAFE_MODE)
		mux_state = USB_PD_MUX_NONE;

	if (mux_state == USB_PD_MUX_NONE)
		return tusb544_enter_low_power_mode(me);

	rv = tusb544_read(me, TUSB544_REG_GENERAL4, &reg);
	if (rv)
		return rv;

	if (mux_state & USB_PD_MUX_POLARITY_INVERTED)
		reg |= TUSB544_GEN4_FLIP_SEL;
	else
		reg &= ~TUSB544_GEN4_FLIP_SEL;

	reg &= ~TUSB544_GEN4_CTL_SEL;

	if (IS_ENABLED(CONFIG_TUSB544_EQ_BY_REGISTER))
		reg |= TUSB544_GEN4_EQ_OVRD;

	if ((mux_state & USB_PD_MUX_USB_ENABLED) &&
	    (mux_state & USB_PD_MUX_DP_ENABLED)) {
		reg |= TUSB544_CTL_SEL_DP_USB;
		reg |= TUSB544_GEN4_HPDIN;
	} else if (mux_state & USB_PD_MUX_DP_ENABLED) {
		reg |= TUSB544_CTL_SEL_DP_ONLY;
		reg |= TUSB544_GEN4_HPDIN;
	} else if (mux_state & USB_PD_MUX_USB_ENABLED)
		reg |= TUSB544_CTL_SEL_USB_ONLY;

	rv = tusb544_write(me, TUSB544_REG_GENERAL4, reg);
	if (rv)
		return rv;

	rv = tusb544_read(me, TUSB544_REG_GENERAL6, &reg);
	if (rv)
		return rv;

	reg &= ~TUSB544_GEN6_DIR_SEL;
	/* All chromebooks are DP SRC */
	reg |= TUSB544_DIR_SEL_USB_DP_SRC;

	return tusb544_write(me, TUSB544_REG_GENERAL6, reg);
}

const struct usb_mux_driver tusb544_drv = {
	.enter_low_power_mode = &tusb544_enter_low_power_mode,
	.init = &tusb544_init,
	.set = &tusb544_set_mux,
};