1 /*
2  * Copyright 2022 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @defgroup driver_bc12_tests
9  * @ingroup all_tests
10  * @{
11  * @defgroup t_bc12_portable_device
12  * @brief TestPurpose: Verify BC1.2 devices in portable device mode.
13  * @}
14  */
15 
16 #include <zephyr/drivers/usb/usb_bc12.h>
17 #include <zephyr/drivers/usb/emul_bc12.h>
18 #include <zephyr/ztest.h>
19 
20 #include <zephyr/logging/log.h>
21 
22 #define LOG_MODULE_NAME test_bc12_pd_mode
23 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
24 
25 struct bc12_pd_mode_fixture {
26 	const struct device *bc12_dev;
27 	const struct emul *bc12_emul;
28 	int callback_count;
29 	bool disconnect_detected;
30 	struct bc12_partner_state partner_state;
31 };
32 
bc12_test_result_cb(const struct device * dev,struct bc12_partner_state * state,void * user_data)33 static void bc12_test_result_cb(const struct device *dev, struct bc12_partner_state *state,
34 				void *user_data)
35 {
36 	struct bc12_pd_mode_fixture *fixture = user_data;
37 
38 	fixture->callback_count++;
39 
40 	if (state) {
41 		if (state->bc12_role == BC12_PORTABLE_DEVICE) {
42 			LOG_INF("charging partner: type %d, voltage %d, current %d", state->type,
43 				state->voltage_uv, state->current_ua);
44 		} else if (state->bc12_role == BC12_CHARGING_PORT) {
45 			LOG_INF("portable device partner: connected %d",
46 				state->pd_partner_connected);
47 		}
48 		fixture->partner_state = *state;
49 	} else {
50 		LOG_INF("callback: partner disconnect");
51 		fixture->disconnect_detected = true;
52 		fixture->partner_state.type = BC12_TYPE_NONE;
53 		fixture->partner_state.current_ua = 0;
54 		fixture->partner_state.voltage_uv = 0;
55 	}
56 }
57 
ZTEST_USER_F(bc12_pd_mode,test_bc12_no_charging_partner)58 ZTEST_USER_F(bc12_pd_mode, test_bc12_no_charging_partner)
59 {
60 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_NONE);
61 
62 	bc12_set_role(fixture->bc12_dev, BC12_PORTABLE_DEVICE);
63 
64 	k_sleep(K_MSEC(100));
65 
66 	/* Without any device connected, our callback should not execute */
67 	zassert_equal(fixture->callback_count, 0);
68 }
69 
ZTEST_USER_F(bc12_pd_mode,test_bc12_sdp_charging_partner)70 ZTEST_USER_F(bc12_pd_mode, test_bc12_sdp_charging_partner)
71 {
72 	/* Connect a SDP charging partner to the emulator */
73 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_SDP);
74 
75 	/* Report to the BC1.2 driver that VBUS is present */
76 	bc12_set_role(fixture->bc12_dev, BC12_PORTABLE_DEVICE);
77 
78 	k_sleep(K_MSEC(100));
79 
80 	/*
81 	 * Note that in SDP mode, the USB device is limited to 2.5 mA until
82 	 * the USB bus is not suspended or the USB device configured.
83 	 *
84 	 * The BC1.2 driver contract specifies to set the current to Isusp
85 	 * for SDP ports or when BC1.2 detection fails.
86 	 */
87 	zassert_equal(fixture->callback_count, 1);
88 	zassert_equal(fixture->partner_state.bc12_role, BC12_PORTABLE_DEVICE);
89 	zassert_equal(fixture->partner_state.type, BC12_TYPE_SDP);
90 	zassert_equal(fixture->partner_state.current_ua, 2500);
91 	zassert_equal(fixture->partner_state.voltage_uv, 5000 * 1000);
92 
93 	/* Remove the charging partner */
94 	fixture->callback_count = 0;
95 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_NONE);
96 
97 	/* Report to the BC1.2 driver that VBUS is no longer present */
98 	bc12_set_role(fixture->bc12_dev, BC12_DISCONNECTED);
99 
100 	k_sleep(K_MSEC(100));
101 
102 	/* The BC1.2 driver should invoke the callback on disconnects */
103 	zassert_equal(fixture->callback_count, 1);
104 	zassert_equal(fixture->partner_state.type, BC12_TYPE_NONE);
105 	zassert_equal(fixture->partner_state.current_ua, 0);
106 	zassert_equal(fixture->partner_state.voltage_uv, 0);
107 }
108 
ZTEST_USER_F(bc12_pd_mode,test_bc12_cdp_charging_partner)109 ZTEST_USER_F(bc12_pd_mode, test_bc12_cdp_charging_partner)
110 {
111 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_CDP);
112 
113 	bc12_set_role(fixture->bc12_dev, BC12_PORTABLE_DEVICE);
114 
115 	k_sleep(K_MSEC(100));
116 
117 	zassert_equal(fixture->callback_count, 1);
118 	zassert_equal(fixture->partner_state.bc12_role, BC12_PORTABLE_DEVICE);
119 	zassert_equal(fixture->partner_state.type, BC12_TYPE_CDP);
120 	zassert_equal(fixture->partner_state.current_ua, 1500 * 1000);
121 	zassert_equal(fixture->partner_state.voltage_uv, 5000 * 1000);
122 
123 	/* Remove the charging partner */
124 	fixture->callback_count = 0;
125 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_NONE);
126 
127 	/* Report to the BC1.2 driver that VBUS is no longer present */
128 	bc12_set_role(fixture->bc12_dev, BC12_DISCONNECTED);
129 
130 	k_sleep(K_MSEC(100));
131 
132 	/* The BC1.2 driver should invoke the callback on disconnects */
133 	zassert_equal(fixture->callback_count, 1);
134 	zassert_true(fixture->disconnect_detected);
135 	zassert_equal(fixture->partner_state.type, BC12_TYPE_NONE);
136 	zassert_equal(fixture->partner_state.current_ua, 0);
137 	zassert_equal(fixture->partner_state.voltage_uv, 0);
138 }
139 
ZTEST_USER_F(bc12_pd_mode,test_bc12_sdp_to_dcp_charging_partner)140 ZTEST_USER_F(bc12_pd_mode, test_bc12_sdp_to_dcp_charging_partner)
141 {
142 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_SDP);
143 
144 	bc12_set_role(fixture->bc12_dev, BC12_PORTABLE_DEVICE);
145 
146 	k_sleep(K_MSEC(100));
147 
148 	zassert_equal(fixture->callback_count, 1);
149 	zassert_equal(fixture->partner_state.bc12_role, BC12_PORTABLE_DEVICE);
150 	zassert_equal(fixture->partner_state.type, BC12_TYPE_SDP);
151 	zassert_equal(fixture->partner_state.current_ua, 2500);
152 	zassert_equal(fixture->partner_state.voltage_uv, 5000 * 1000);
153 
154 	/* Change the partner type to DCP */
155 	fixture->callback_count = 0;
156 	bc12_emul_set_charging_partner(fixture->bc12_emul, BC12_TYPE_DCP);
157 
158 	/* Trigger a new detection */
159 	bc12_set_role(fixture->bc12_dev, BC12_PORTABLE_DEVICE);
160 
161 	k_sleep(K_MSEC(100));
162 
163 	/* The BC1.2 driver should invoke the callback once to report the new state. */
164 	zassert_equal(fixture->callback_count, 1);
165 	zassert_equal(fixture->partner_state.bc12_role, BC12_PORTABLE_DEVICE);
166 	zassert_equal(fixture->partner_state.type, BC12_TYPE_DCP);
167 	zassert_equal(fixture->partner_state.current_ua, 1500 * 1000);
168 	zassert_equal(fixture->partner_state.voltage_uv, 5000 * 1000);
169 }
170 
bc12_before(void * data)171 static void bc12_before(void *data)
172 {
173 	struct bc12_pd_mode_fixture *fixture = data;
174 
175 	fixture->callback_count = 0;
176 	fixture->disconnect_detected = 0;
177 	memset(&fixture->partner_state, 0, sizeof(struct bc12_partner_state));
178 
179 	bc12_set_result_cb(fixture->bc12_dev, &bc12_test_result_cb, fixture);
180 }
181 
bc12_after(void * data)182 static void bc12_after(void *data)
183 {
184 	struct bc12_pd_mode_fixture *fixture = data;
185 
186 	bc12_set_result_cb(fixture->bc12_dev, NULL, NULL);
187 	bc12_set_role(fixture->bc12_dev, BC12_DISCONNECTED);
188 }
189 
bc12_setup(void)190 static void *bc12_setup(void)
191 {
192 	static struct bc12_pd_mode_fixture fixture = {
193 		.bc12_dev = DEVICE_DT_GET(DT_ALIAS(bc12)),
194 		.bc12_emul = EMUL_DT_GET(DT_ALIAS(bc12)),
195 	};
196 
197 	zassert_not_null(fixture.bc12_dev);
198 	zassert_not_null(fixture.bc12_emul);
199 	zassert_true(device_is_ready(fixture.bc12_dev));
200 
201 	return &fixture;
202 }
203 
204 ZTEST_SUITE(bc12_pd_mode, NULL, bc12_setup, bc12_before, bc12_after, NULL);
205