SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
AXP517Tcpc.cpp
Go to the documentation of this file.
1
30#include "../../../SensorBuildOpt.h"
31#if !SENSORLIB_EXCLUDE_PMIC_AXP517
32
33#include "AXP517Tcpc.hpp"
34#include "AXP517Regs.hpp"
35#include "AXP517TcpcRegs.hpp"
36
37using namespace axp517::tcpc;
38
39namespace
40{
41static constexpr uint8_t POWER_STATUS_UNINIT = (1u << 6);
42static constexpr uint8_t POWER_STATUS_VBUS_PRESENT = (1u << 2);
43
44static constexpr uint8_t ROLE_CTRL_SINK_RD_RD = 0x0A;
45static constexpr uint8_t ROLE_CTRL_OPEN_OPEN = 0x0F;
46static constexpr uint8_t ALERT_MASK_IRQ_VALUE = 0x77;
47static constexpr uint8_t POWER_STATUS_MASK_VALUE = 0x04;
48static constexpr uint8_t MSG_HDR_PD20_SINK_UFP = 0x02;
49static constexpr uint8_t RX_DETECT_SOP = 0x01;
50static constexpr uint8_t ADC_VBUS_ENABLE = 0x04;
51} // namespace
52
53bool AXP517Tcpc::r8(uint8_t reg, uint8_t &out)
54{
55 int v = _core.readReg(reg);
56 if (v < 0) return false;
57 out = static_cast<uint8_t>(v);
58 return true;
59}
60
61bool AXP517Tcpc::w8(uint8_t reg, uint8_t v)
62{
63 return _core.writeReg(reg, v) >= 0;
64}
65
66bool AXP517Tcpc::readNoInc(uint8_t reg, uint8_t *buf, uint8_t len)
67{
68 _core.setAck(false);
69 bool ok = _core.readRegBuff(reg, buf, len) >= 0;
70 _core.setAck(true);
71 return ok;
72}
73
74bool AXP517Tcpc::writeNoInc(uint8_t reg, const uint8_t *buf, uint8_t len)
75{
76 if (!buf && len) return false;
77
78 for (uint8_t i = 0; i < len; ++i) {
79 if (!w8(reg, buf[i])) return false;
80 }
81 return true;
82}
83
85{
86 if (!_core.enableModule(AXP517Core::Module::TYPEC, true)) {
87 return false;
88 }
89 _core.delayMs(20);
90
91 if (!w8(CC_GENERAL_CONTROL, SW_RESET)) return false;
92 _core.delayMs(50);
93 if (!w8(CC_GENERAL_CONTROL, 0x00)) return false;
94 _core.delayMs(300);
95
96 for (uint8_t i = 0; i < 40; ++i) {
97 uint8_t status = 0;
98 if (!r8(POWER_STATUS, status)) return false;
99 if ((status & POWER_STATUS_UNINIT) == 0) break;
100 _core.delayMs(50);
101 }
102
103 uint8_t status = 0;
104 if (!r8(POWER_STATUS, status)) return false;
105 if (status & POWER_STATUS_UNINIT) return false;
106
107 if (!w8(FAULT_STATUS, 0xFF)) return false;
108 if (!w8(CC_CONNECTION_STATUS, 0xFF)) return false;
109
110 if (!w8(ROLE_CONTROL, ROLE_CTRL_SINK_RD_RD)) return false;
111 if (!w8(TCPC_CONTROL, 0x00)) return false;
112
113 // Do not write PD_STATE/AWAKE_EN here. The verified Python flow leaves the
114 // low-power/awake registers untouched so the BMC PHY keeps receiving PD frames.
115 if (!w8(TWI_ADDR_STATIC, 0x01)) return false;
116
117 if (!clearAllAlerts()) return false;
118 if (!w8(POWER_STATUS_MASK, POWER_STATUS_MASK_VALUE)) return false;
119 if (!w8(COMMAND, cmd::ENABLE_VBUS_DETECT)) return false;
120 if (!w8(PD_ALERT_MASKL, ALERT_MASK_IRQ_VALUE)) return false;
121 if (!w8(PD_ALERT_MASKH, 0x00)) return false;
122
123 if (!w8(POWER_CONTROL, 0x10)) return false;
124
125 uint8_t adc = 0;
126 if (!r8(axp517_regs::adc::ENABLE, adc)) return false;
127 if (!w8(axp517_regs::adc::ENABLE, static_cast<uint8_t>(adc | ADC_VBUS_ENABLE))) return false;
128
129 if (!clearTx()) return false;
130 if (!clearAllAlerts()) return false;
131 if (!setSinkMessageHeaderAndRx()) return false;
132
133 // Force a Type-C detach/attach when the charger is already plugged in, so
134 // the Source re-sends Source_Capabilities after RX is enabled.
135 if (!w8(ROLE_CONTROL, ROLE_CTRL_OPEN_OPEN)) return false;
136 _core.delayMs(400);
137 if (!w8(ROLE_CONTROL, ROLE_CTRL_SINK_RD_RD)) return false;
138 _core.delayMs(150);
139
140 if (!setPolarityFromCc()) return false;
141 return clearAllAlerts();
142}
143
145{
146 uint8_t lo = 0, hi = 0;
147 if (!r8(TCPC_VENDOR_ID, lo)) return false;
148 if (!r8(TCPC_VENDOR_ID + 1, hi)) return false;
149
150 uint16_t vid = static_cast<uint16_t>(lo) | (static_cast<uint16_t>(hi) << 8);
151 return vid == VENDOR_ID || vid == 0xE0C5;
152}
153
154bool AXP517Tcpc::readAlert(uint16_t &out)
155{
156 uint8_t lo = 0, hi = 0;
157 if (!r8(PD_ALERTL, lo)) return false;
158 if (!r8(PD_ALERTH, hi)) return false;
159 out = static_cast<uint16_t>(lo) | (static_cast<uint16_t>(hi) << 8);
160 return true;
161}
162
163bool AXP517Tcpc::clearAlert(uint16_t maskRw1c)
164{
165 if (!w8(PD_ALERTL, static_cast<uint8_t>(maskRw1c & 0xFF))) return false;
166 return w8(PD_ALERTH, static_cast<uint8_t>((maskRw1c >> 8) & 0xFF));
167}
168
170{
171 return r8(FAULT_STATUS, out);
172}
173
174bool AXP517Tcpc::clearFaultStatus(uint8_t maskRw1c)
175{
176 return w8(FAULT_STATUS, maskRw1c);
177}
178
180{
181 uint8_t status = 0;
182 for (uint8_t reg = axp517_regs::irq::STATUS0; reg <= axp517_regs::irq::STATUS3; ++reg) {
183 if (!r8(reg, status)) return false;
184 if (status && !w8(reg, status)) return false;
185 }
186 return true;
187}
188
190{
191 return w8(MESSAGE_HEADER_INFO, v);
192}
193
195{
196 return w8(RECEIVE_DETECT, v);
197}
198
200{
201 if (!w8(TX_BYTE_CNT, 0x00)) return false;
202 return w8(TX_BUF_TRANSMIT, 0x00);
203}
204
206{
207 if (!w8(MESSAGE_HEADER_INFO, MSG_HDR_PD20_SINK_UFP)) return false;
208 return w8(RECEIVE_DETECT, RX_DETECT_SOP);
209}
210
212{
213 uint8_t cc = 0;
214 if (!r8(CC_STATUS, cc)) return false;
215
216 uint8_t cc1 = cc & 0x03;
217 uint8_t cc2 = (cc >> 2) & 0x03;
218 return w8(TCPC_CONTROL, (cc2 != 0 && cc1 == 0) ? 0x01 : 0x00);
219}
220
222{
223 uint8_t cc = 0;
224 if (!r8(CC_STATUS, cc)) return false;
225
226 auto decodeSinkCc = [](uint8_t raw) -> CcStatus {
227 switch (raw & 0x03)
228 {
229 case 1: return CcStatus::RP_DEF;
230 case 2: return CcStatus::RP_1_5;
231 case 3: return CcStatus::RP_3_0;
232 default: return CcStatus::OPEN;
233 }
234 };
235
236 cc1 = decodeSinkCc(cc);
237 cc2 = decodeSinkCc(cc >> 2);
238 return true;
239}
240
242{
245 if (!getCc(cc1, cc2)) return false;
246 return cc1 != CcStatus::OPEN || cc2 != CcStatus::OPEN;
247}
248
249bool AXP517Tcpc::getPowerStatus(uint8_t &status)
250{
251 return r8(POWER_STATUS, status);
252}
253
255{
256 uint8_t status = 0;
257 if (!getPowerStatus(status)) return false;
258 return (status & POWER_STATUS_VBUS_PRESENT) != 0;
259}
260
261bool AXP517Tcpc::readVbusMv(uint16_t &mv)
262{
263 uint8_t lo = 0, hi = 0;
264 if (!r8(VBUS_VOLTAGE_L, lo)) return false;
265 if (!r8(VBUS_VOLTAGE_H, hi)) return false;
266
267 uint16_t raw = static_cast<uint16_t>(lo) | (static_cast<uint16_t>(hi & 0x07) << 8);
268 mv = static_cast<uint16_t>(raw * 14);
269 return true;
270}
271
273{
274 out = RxFifoMsg{};
275
276 uint8_t buf[32] = {0};
277 if (!readNoInc(RX_BYTE_CNT, buf, sizeof(buf))) return false;
278
279 uint8_t count = buf[0];
280 uint8_t frameType = buf[1];
281 if (count == 0 || count > 30 || count < 3) return false;
282 if (frameType != 0x00 && frameType != 0x01) return false;
283
284 out.byteCount = count;
285 out.frameType = frameType;
286 out.headerLE = static_cast<uint16_t>(buf[2]) | (static_cast<uint16_t>(buf[3]) << 8);
287
288 uint8_t payloadLen = static_cast<uint8_t>(count - 3);
289 if (payloadLen > sizeof(out.payload)) payloadLen = sizeof(out.payload);
290 out.payloadLen = payloadLen;
291 for (uint8_t i = 0; i < payloadLen; ++i) {
292 out.payload[i] = buf[4 + i];
293 }
294
295 return true;
296}
297
298bool AXP517Tcpc::txSend(TransmitType type, RetryCount retry, uint16_t headerLE,
299 const uint8_t *payload, uint8_t payloadLen)
300{
301 if (payloadLen > 28) payloadLen = 28;
302 if (payloadLen && !payload) return false;
303
304 bool orderedSet = type == TransmitType::HARD_RESET || type == TransmitType::CABLE_RESET;
305 if (!orderedSet) {
306 uint8_t buf[31] = {0};
307 buf[0] = static_cast<uint8_t>(payloadLen + 2);
308 buf[1] = static_cast<uint8_t>(headerLE & 0xFF);
309 buf[2] = static_cast<uint8_t>((headerLE >> 8) & 0xFF);
310 for (uint8_t i = 0; i < payloadLen; ++i) {
311 buf[3 + i] = payload[i];
312 }
313 if (!writeNoInc(TX_BYTE_CNT, buf, static_cast<uint8_t>(payloadLen + 3))) {
314 return false;
315 }
316 }
317
318 uint8_t retryValue = orderedSet ? 0 : static_cast<uint8_t>(retry);
319 uint8_t tx = static_cast<uint8_t>(((retryValue & 0x03) << 4) |
320 (static_cast<uint8_t>(type) & 0x07));
321 return w8(TX_BUF_TRANSMIT, tx);
322}
323
324#endif
@license MIT License
@license MIT License
@license MIT License
void delayMs(uint32_t ms)
Delay using the active platform HAL.
bool enableModule(Module module, bool enable)
Enable or disable a module.
@ TYPEC
REG 0BH bit 3 Type-C.
bool writeMessageHeaderInfo(uint8_t v)
Write the TCPCI MESSAGE_HEADER_INFO register.
bool clearAlert(uint16_t maskRw1c)
Clear PD_ALERTL/H bits using write-one-to-clear semantics.
bool setSinkMessageHeaderAndRx()
Configure sink message-header defaults and enable SOP RX.
bool clearPmicIrqStatus()
Clear the non-PD PMIC IRQ status registers.
bool init()
Initialize the TCPC as a USB-PD sink.
bool clearTx()
Reset the TX byte count and transmit command register.
bool txSend(TransmitType type, RetryCount retry, uint16_t headerLE, const uint8_t *payload, uint8_t payloadLen)
Send a USB-PD packet through the TCPC TX FIFO.
bool clearFaultStatus(uint8_t maskRw1c)
Clear TCPC FAULT_STATUS bits using write-one-to-clear semantics.
bool isAttached()
Check whether either CC pin indicates attachment.
RetryCount
TCPCI transmit retry count values.
bool readFaultStatus(uint8_t &out)
Read the TCPC FAULT_STATUS register.
bool getCc(CcStatus &cc1, CcStatus &cc2)
Read and decode CC1/CC2 status.
CcStatus
Decoded sink-side CC status.
@ RP_1_5
1.5 A current advertisement.
@ RP_DEF
Default USB current advertisement.
@ OPEN
No source detected on this CC pin.
@ RP_3_0
3.0 A current advertisement.
bool writeReceiveDetect(uint8_t v)
Write the TCPCI RECEIVE_DETECT register.
bool readVbusMv(uint16_t &mv)
Read TCPC VBUS ADC value.
bool readAlert(uint16_t &out)
Read PD_ALERTL/H.
bool rxReadMessage(RxFifoMsg &out)
Read and decode one TCPC RX FIFO message.
bool checkVendorId()
Verify the TCPC vendor ID.
bool getPowerStatus(uint8_t &status)
Read POWER_STATUS.
bool clearAllAlerts()
Clear all PD alert bits.
TransmitType
TCPCI TRANSMIT register packet type values.
@ HARD_RESET
Hard Reset ordered set.
@ CABLE_RESET
Cable Reset ordered set.
bool isVbusPresent()
Check whether TCPC VBUS present status is set.
bool setPolarityFromCc()
Set TCPC polarity from the current CC status.
int readReg(uint8_t reg) const
int writeReg(uint8_t reg, uint8_t val)
int readRegBuff(uint8_t reg, uint8_t *buf, size_t len) const
void setAck(bool enable)
AXP517 TCPC register addresses, alert bits, and command constants.
uint8_t i
char buf[64]
Decoded RX FIFO message.
uint16_t headerLE
USB-PD message header in little-endian order.
uint8_t frameType
TCPCI RX frame type.
uint8_t byteCount
TCPCI readable byte count.
uint8_t payload[28]
USB-PD payload bytes.
uint8_t payloadLen
Number of valid payload bytes.
static constexpr uint8_t ENABLE
ADC channel enable control.
static constexpr uint8_t STATUS3
IRQ Status 3.
static constexpr uint8_t STATUS0
IRQ Status 0.