summaryrefslogtreecommitdiff
path: root/common/usb_charge.c
blob: eea5d3ec7276f1057d98e67c09f4a60cb0a83ca9 (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
/* 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 charging control module for Chrome EC */

#include "board.h"
#include "chipset.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "usb_charge.h"
#include "util.h"


static void usb_charge_set_control_mode(int port_id, int mode)
{
	if (port_id == 0) {
		gpio_set_level(GPIO_USB1_CTL1, (mode & 0x4) >> 2);
		gpio_set_level(GPIO_USB1_CTL2, (mode & 0x2) >> 1);
		gpio_set_level(GPIO_USB1_CTL3, mode & 0x1);
	}
	else if (port_id == 1) {
		gpio_set_level(GPIO_USB2_CTL1, (mode & 0x4) >> 2);
		gpio_set_level(GPIO_USB2_CTL2, (mode & 0x2) >> 1);
		gpio_set_level(GPIO_USB2_CTL3, mode & 0x1);
	}
}


static void usb_charge_set_enabled(int port_id, int en)
{
	if (port_id == 0)
		gpio_set_level(GPIO_USB1_ENABLE, en);
	else
		gpio_set_level(GPIO_USB2_ENABLE, en);
}


static void usb_charge_set_ilim(int port_id, int sel)
{
	if (port_id == 0)
		gpio_set_level(GPIO_USB1_ILIM_SEL, sel);
	else
		gpio_set_level(GPIO_USB2_ILIM_SEL, sel);
}


static int usb_charge_all_ports_on(void)
{
	usb_charge_set_mode(0, USB_CHARGE_MODE_DOWNSTREAM_500MA);
	usb_charge_set_mode(1, USB_CHARGE_MODE_DOWNSTREAM_500MA);
	return EC_SUCCESS;
}


static int usb_charge_all_ports_off(void)
{
	usb_charge_set_mode(0, USB_CHARGE_MODE_DISABLED);
	usb_charge_set_mode(1, USB_CHARGE_MODE_DISABLED);
	return EC_SUCCESS;
}


int usb_charge_set_mode(int port_id, enum usb_charge_mode mode)
{
	if (port_id >= USB_CHARGE_PORT_COUNT)
		return EC_ERROR_INVAL;

	if (mode == USB_CHARGE_MODE_DISABLED) {
		usb_charge_set_enabled(port_id, 0);
		return EC_SUCCESS;
	}
	else
		usb_charge_set_enabled(port_id, 1);

	switch (mode) {
		case USB_CHARGE_MODE_CHARGE_AUTO:
			usb_charge_set_control_mode(port_id, 1);
			usb_charge_set_ilim(port_id, 1);
			break;
		case USB_CHARGE_MODE_CHARGE_BC12:
			usb_charge_set_control_mode(port_id, 4);
			break;
		case USB_CHARGE_MODE_DOWNSTREAM_500MA:
			usb_charge_set_control_mode(port_id, 2);
			usb_charge_set_ilim(port_id, 0);
			break;
		case USB_CHARGE_MODE_DOWNSTREAM_1500MA:
			usb_charge_set_control_mode(port_id, 2);
			usb_charge_set_ilim(port_id, 1);
			break;
		default:
			return EC_ERROR_UNKNOWN;
	}

	return EC_SUCCESS;
}

/*****************************************************************************/
/* Console commands */

static int command_set_mode(int argc, char **argv)
{
	int port_id = -1;
	int mode = -1;
	char* endptr;

	if (argc != 3) {
		ccputs("Usage: usbchargemode <port_id> <mode>\n");
		ccputs("Modes: 0=Disabled.\n"
		       "       1=Dedicated charging. Auto select.\n"
		       "       2=Dedicated charging. BC 1.2.\n"
		       "       3=Downstream. Max 500mA.\n"
		       "       4=Downstream. Max 1.5A.\n");
		return EC_ERROR_UNKNOWN;
	}

	port_id = strtoi(argv[1], &endptr, 0);
	if (*endptr || port_id < 0 || port_id >= USB_CHARGE_PORT_COUNT) {
		ccputs("Invalid port ID.\n");
		return EC_ERROR_UNKNOWN;
	}

	mode = strtoi(argv[2], &endptr, 0);
	if (*endptr || mode < 0 || mode >= USB_CHARGE_MODE_COUNT) {
		ccputs("Invalid mode.\n");
		return EC_ERROR_UNKNOWN;
	}

	ccprintf("Setting USB mode...\n");
	return usb_charge_set_mode(port_id, mode);
}
DECLARE_CONSOLE_COMMAND(usbchargemode, command_set_mode);

/*****************************************************************************/
/* Hooks */

static int usb_charge_init(void)
{
	if (chipset_in_state(CHIPSET_STATE_SOFT_OFF))
		usb_charge_all_ports_off();
	else
		usb_charge_all_ports_on();

	return EC_SUCCESS;
}
DECLARE_HOOK(HOOK_INIT, usb_charge_init, HOOK_PRIO_DEFAULT);


static int usb_charge_startup(void)
{
	/* Turn on USB ports on as we go into S3 or S0. */
	usb_charge_all_ports_on();
	return EC_SUCCESS;
}
DECLARE_HOOK(HOOK_CHIPSET_STARTUP, usb_charge_startup, HOOK_PRIO_DEFAULT);


static int usb_charge_shutdown(void)
{
	/* Turn on USB ports off as we go back to S5. */
	usb_charge_all_ports_off();
	return EC_SUCCESS;
}
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, usb_charge_shutdown, HOOK_PRIO_DEFAULT);