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