summaryrefslogtreecommitdiff
path: root/common/usb_charger.c
blob: b8e8038811fbf1096f5a5acc3d115a4de7feef67 (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
/* Copyright 2015 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 charger interface routines. This code assumes that CONFIG_CHARGE_MANAGER
 * is defined and implemented.
 * usb_charger_set_switches() must be implemented by a companion
 * usb_switch driver.
 * In addition,  USB switch-specific usb_charger task or interrupt routine
 * is necessary to update charge_manager with detected charger attributes.
 */

#include "charge_manager.h"
#include "charger.h"
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "stddef.h"
#include "task.h"
#include "usb_charge.h"
#include "usb_pd.h"
#include "usb_pd_flags.h"
#include "usbc_ppc.h"
#include "util.h"

static void update_vbus_supplier(int port, int vbus_level)
{
	struct charge_port_info charge = {0};

	if (vbus_level && !usb_charger_port_is_sourcing_vbus(port)) {
		charge.voltage = USB_CHARGER_VOLTAGE_MV;
		charge.current = USB_CHARGER_MIN_CURR_MA;
	}

	charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, port, &charge);
}

#ifdef CONFIG_USB_PD_5V_EN_CUSTOM
#define USB_5V_EN(port) board_is_sourcing_vbus(port)
#elif defined(CONFIG_USBC_PPC)
#define USB_5V_EN(port) ppc_is_sourcing_vbus(port)
#elif defined(CONFIG_USB_PD_PPC)
#define USB_5V_EN(port) tcpci_tcpm_get_src_ctrl(port)
#elif defined(CONFIG_USB_PD_5V_CHARGER_CTRL)
#define USB_5V_EN(port) charger_is_sourcing_otg_power(port)
#elif defined(CONFIG_USB_PD_5V_EN_ACTIVE_LOW)
#define USB_5V_EN(port) !gpio_get_level(GPIO_USB_C##port##_5V_EN_L)
#else
#define USB_5V_EN(port) gpio_get_level(GPIO_USB_C##port##_5V_EN)
#endif

int usb_charger_port_is_sourcing_vbus(int port)
{
	if (port == 0)
		return USB_5V_EN(0);
#if CONFIG_USB_PD_PORT_MAX_COUNT >= 2
	else if (port == 1)
		return USB_5V_EN(1);
#endif
	/* Not a valid port */
	return 0;
}

void usb_charger_vbus_change(int port, int vbus_level)
{
	/* If VBUS has transitioned low, notify PD module directly */
	if (!vbus_level)
		pd_vbus_low(port);

	/* Update VBUS supplier and signal VBUS change to USB_CHG task */
	update_vbus_supplier(port, vbus_level);

#ifdef HAS_TASK_USB_CHG_P0
	/* USB Charger task(s) */
	task_set_event(USB_CHG_PORT_TO_TASK_ID(port), USB_CHG_EVENT_VBUS);

	/* If we swapped to sourcing, drop any related charge suppliers */
	if (usb_charger_port_is_sourcing_vbus(port))
		usb_charger_reset_charge(port);
#endif

	if ((get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_CHARGER) ||
		(get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_PPC)) {
		/* USB PD task */
		task_wake(PD_PORT_TO_TASK_ID(port));
	}
}

void usb_charger_reset_charge(int port)
{
	charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY,
				     port, NULL);
	charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP,
				     port, NULL);
	charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP,
				     port, NULL);
	charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP,
				     port, NULL);
	charge_manager_update_charge(CHARGE_SUPPLIER_OTHER,
				     port, NULL);
#if CONFIG_DEDICATED_CHARGE_PORT_COUNT > 0
	charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED,
				     port, NULL);
#endif
#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7
	charge_manager_update_charge(CHARGE_SUPPLIER_WPC_BPP,
				     port, NULL);
	charge_manager_update_charge(CHARGE_SUPPLIER_WPC_EPP,
				     port, NULL);
	charge_manager_update_charge(CHARGE_SUPPLIER_WPC_GPP,
				     port, NULL);
#endif

}

static void usb_charger_init(void)
{
	int i;
	for (i = 0; i < board_get_usb_pd_port_count(); i++) {
		usb_charger_reset_charge(i);
		/* Initialize VBUS supplier based on whether VBUS is present. */
		update_vbus_supplier(i, pd_is_vbus_present(i));
	}
}
DECLARE_HOOK(HOOK_INIT, usb_charger_init, HOOK_PRIO_CHARGE_MANAGER_INIT + 1);

void usb_charger_task(void *u)
{
	int port = TASK_ID_TO_USB_CHG_PORT(task_get_current());

	ASSERT(bc12_ports[port].drv->usb_charger_task);
	bc12_ports[port].drv->usb_charger_task(port);
}