summaryrefslogtreecommitdiff
path: root/driver/bc12/max14637.c
blob: b2e734e1c0bb10485c0e131d0fa49f687836c2ab (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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/* Copyright 2017 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.
 */

/*
 * MAX14637 USB BC 1.2 Charger Detector driver.
 *
 * NOTE: The driver assumes that CHG_AL_N and SW_OPEN are not connected,
 * therefore the value of CHG_DET indicates whether the source is NOT a
 * low-power standard downstream port (SDP).  In order to use higher currents,
 * the system will have to charge ramp.
 */

#include "max14637.h"
#include "charge_manager.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "power.h"
#include "power/cannonlake.h"
#include "task.h"
#include "tcpm/tcpm.h"
#include "timer.h"
#include "usb_charge.h"
#include "usb_pd.h"
#include "util.h"

#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)

#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
/**
 * Returns true if the charger detect pin is activated.
 *
 * @parm cfg driver for chip to read the charger detect pin for.
 * @return 1 if charger detect is activated (high when active high or
 *	low with active low), otherwise 0.
 */
static int is_chg_det_activated(const struct max14637_config_t * const cfg)
{
	return !!gpio_get_level(cfg->chg_det_pin) ^
		!!(cfg->flags & MAX14637_FLAGS_CHG_DET_ACTIVE_LOW);
}
#endif

/**
 * Activates the Chip Enable GPIO based on the enabled value.
 *
 * @param cfg driver for chip that will set chip enable gpio.
 * @param enable 1 to activate gpio (high for active high and low for active
 *	low).
 */
static void activate_chip_enable(
	const struct max14637_config_t * const cfg, const int enable)
{
	gpio_set_level(
		cfg->chip_enable_pin,
		!!enable ^ !!(cfg->flags & MAX14637_FLAGS_ENABLE_ACTIVE_LOW));
}

/**
 * Update BC1.2 detected status to charge manager.
 *
 * @param port: The Type-C port where VBUS is present.
 */
static void update_bc12_status_to_charger_manager(const int port)
{
	const struct max14637_config_t * const cfg = &max14637_config[port];
	struct charge_port_info new_chg;

	new_chg.voltage = USB_CHARGER_VOLTAGE_MV;
#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
	/*
	 * The driver assumes that CHG_AL_N and SW_OPEN are not connected,
	 * therefore an activated CHG_DET indicates whether the source is NOT a
	 * low-power standard downstream port (SDP). The system will have to
	 * ramp the current to determine the limit.  The Type-C spec prohibits
	 * proprietary methods now, therefore 1500mA is the max.
	 */
	new_chg.current = is_chg_det_activated(cfg) ? USB_CHARGER_MAX_CURR_MA :
						      500;
#else
	/*
	 * If the board doesn't support charge ramping, then assume the lowest
	 * denominator; that is assume the charger detected is a weak dedicated
	 * charging port (DCP) which can only supply 500mA.
	 */
	new_chg.current = 500;
#endif /* !defined(CONFIG_CHARGE_RAMP_SW && CONFIG_CHARGE_RAMP_HW) */

	charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, port, &new_chg);
}

/**
 * Perform BC1.2 detection.
 *
 * @param port: The Type-C port where VBUS is present.
 */
static void bc12_detect(const int port)
{
	const struct max14637_config_t * const cfg = &max14637_config[port];

	/*
	 * Enable the IC to begin detection and connect switches if
	 * necessary. This is only necessary if the port power role is a
	 * sink. If the power role is a source then just keep the max14637
	 * powered on so that data switches are close. Note that the gpio enable
	 * for this chip is active by default. In order to trigger bc1.2
	 * detection, the chip enable must be driven low, then high again so the
	 * chip will start bc1.2 client side detection. Add a 100 msec delay to
	 * avoid collision with a device that might be doing bc1.2 client side
	 * detection.
	 */
	msleep(100);
	activate_chip_enable(cfg, 0);
	msleep(CONFIG_BC12_MAX14637_DELAY_FROM_OFF_TO_ON_MS);
	activate_chip_enable(cfg, 1);

#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
	/*
	 * Apple or TomTom charger detection can take as long as 600ms.  Wait a
	 * little bit longer for margin.
	 */
	msleep(630);
#endif /* !defined(CONFIG_CHARGE_RAMP_SW && CONFIG_CHARGE_RAMP_HW) */
}

/**
 * If VBUS is present and port power role is sink, then trigger bc1.2 client
 * detection. If VBUS is not present then update charge manager. Note that both
 * chip_enable and VBUS must be active for the IC to be powered up. Chip enable
 * is kept enabled by default so that bc1.2 client detection is not triggered
 * when the port power role is source.
 *
 * @param port: Which USB Type-C port to examine.
 */
static void detect_or_power_down_ic(const int port)
{
	int vbus_present;

#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC
	vbus_present = tcpm_check_vbus_level(port, VBUS_PRESENT);
#else
	vbus_present = pd_snk_is_vbus_provided(port);
#endif /* !defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) */

	if (vbus_present) {
#if defined(CONFIG_POWER_PP5000_CONTROL) && defined(HAS_TASK_CHIPSET)
		/* Turn on the 5V rail to allow the chip to be powered. */
		power_5v_enable(task_get_current(), 1);
#endif
		if (pd_get_power_role(port) == PD_ROLE_SINK) {
			bc12_detect(port);
			update_bc12_status_to_charger_manager(port);
		}
	} else {
		/* Let charge manager know there's no more charge available. */
		charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, port, NULL);
		/*
		 * If latest attached charger is PD Adapter then it would be
		 * detected as DCP and data switch of USB2.0 would be open which
		 * prevents USB 2.0 data path from working later. As a result,
		 * bc12_detect() is called again here and SCP would be detected
		 * due to D+/D- are NC (open) if nothing is attached then data
		 * switch of USB2.0 can be kept close from now on.
		 */
		bc12_detect(port);
#if defined(CONFIG_POWER_PP5000_CONTROL) && defined(HAS_TASK_CHIPSET)
		/* Issue a request to turn off the rail. */
		power_5v_enable(task_get_current(), 0);
#endif
	}
}

static void max14637_usb_charger_task(const int port)
{
	uint32_t evt;
	const struct max14637_config_t * const cfg = &max14637_config[port];

	ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT);
	/*
	 * Have chip enable active as default state so data switches are closed
	 * and bc1.2 client side detection is not activated when the port power
	 * role is a source.
	 */
	activate_chip_enable(cfg, 1);
	/* Check whether bc1.2 client mode detection needs to be triggered */
	detect_or_power_down_ic(port);

	while (1) {
		evt = task_wait_event(-1);

		if (evt & USB_CHG_EVENT_VBUS)
			detect_or_power_down_ic(port);
	}
}

#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
static int max14637_ramp_allowed(int supplier)
{
	/*
	 * Due to the limitations in the application of the MAX14637, we
	 * don't quite know exactly what we're plugged into.  Therefore,
	 * the supplier type will be CHARGE_SUPPLIER_OTHER.
	 */
	return supplier == CHARGE_SUPPLIER_OTHER;
}

static int max14637_ramp_max(int supplier, int sup_curr)
{
	/* Use the current limit that was decided by the MAX14637. */
	if (supplier == CHARGE_SUPPLIER_OTHER)
		return sup_curr;
	else
		return 500;
}
#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */

/* Called on AP S5 -> S3  and S3/S0iX -> S0 transition */
static void bc12_chipset_startup(void)
{
	int port;

	/*
	 * For each port, trigger a new USB_CHG_EVENT_VBUS event to handle cases
	 * where there was no change in VBUS following an AP resume/startup
	 * event. If a legacy charger is connected to the port, then VBUS will
	 * not drop even during the USB PD hard reset.
	 */
	for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++)
		task_set_event(USB_CHG_PORT_TO_TASK_ID(port),
			       USB_CHG_EVENT_VBUS);
}
DECLARE_HOOK(HOOK_CHIPSET_STARTUP, bc12_chipset_startup, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_CHIPSET_RESUME, bc12_chipset_startup, HOOK_PRIO_DEFAULT);

const struct bc12_drv max14637_drv = {
	.usb_charger_task = max14637_usb_charger_task,
#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
	.ramp_allowed = max14637_ramp_allowed,
	.ramp_max = max14637_ramp_max,
#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */
};

#ifdef CONFIG_BC12_SINGLE_DRIVER
/* provide a default bc12_ports[] for backward compatibility */
struct bc12_config bc12_ports[CHARGE_PORT_COUNT] = {
	[0 ... (CHARGE_PORT_COUNT - 1)] = {
		.drv = &max14637_drv,
	},
};
#endif /* CONFIG_BC12_SINGLE_DRIVER */