mirror of
https://github.com/Ralim/IronOS.git
synced 2025-07-23 12:23:06 +02:00
* Update documentation to build IronOS in Windows using MSYS2 environment and fix compilation on case-sensitive file systems. --------- Co-authored-by: Ivan Zorin <ivan.a.zorin@gmail.com>
221 lines
5.7 KiB
C++
221 lines
5.7 KiB
C++
#include "HUB238.hpp"
|
|
#include "I2CBB2.hpp"
|
|
#include "Utils.hpp"
|
|
#include "configuration.h"
|
|
|
|
#if POW_PD_EXT == 1
|
|
bool hub238_probe() { return I2CBB2::probe(HUB238_ADDR); }
|
|
|
|
extern int32_t powerSupplyWattageLimit;
|
|
|
|
uint16_t hub238_debug_state() {
|
|
uint8_t status0 = 0;
|
|
uint8_t status1 = 0;
|
|
if (!I2CBB2::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS0, &status0, 1)) {
|
|
return 0xFFFF;
|
|
}
|
|
if (!I2CBB2::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS1, &status1, 1)) {
|
|
return 0xFFFF;
|
|
}
|
|
return status1 | (((uint16_t)status0) << 8);
|
|
}
|
|
uint16_t pdo_slot_to_currentx100(uint8_t temp) {
|
|
temp = temp & 0b1111;
|
|
switch (temp) {
|
|
case 0b0000:
|
|
return 50;
|
|
case 0b0001:
|
|
return 70;
|
|
case 0b0010:
|
|
return 100;
|
|
case 0b0011:
|
|
return 125;
|
|
case 0b0100:
|
|
return 150;
|
|
case 0b0101:
|
|
return 175;
|
|
case 0b0110:
|
|
return 200;
|
|
case 0b0111:
|
|
return 225;
|
|
case 0b1000:
|
|
return 250;
|
|
case 0b1001:
|
|
return 275;
|
|
case 0b1010:
|
|
return 300;
|
|
case 0b1011:
|
|
return 325;
|
|
case 0b1100:
|
|
return 350;
|
|
case 0b1101:
|
|
return 400;
|
|
case 0b1110:
|
|
return 450;
|
|
case 0b1111:
|
|
return 500;
|
|
}
|
|
}
|
|
uint16_t hub238_getVoltagePDOCurrent(uint8_t voltage) {
|
|
uint8_t reg = HUB238_REG_SRC_PDO_5V;
|
|
switch (voltage) {
|
|
case 5:
|
|
reg = HUB238_REG_SRC_PDO_5V;
|
|
break;
|
|
case 9:
|
|
reg = HUB238_REG_SRC_PDO_9V;
|
|
break;
|
|
case 12:
|
|
reg = HUB238_REG_SRC_PDO_12V;
|
|
break;
|
|
case 15:
|
|
reg = HUB238_REG_SRC_PDO_15V;
|
|
break;
|
|
case 18:
|
|
reg = HUB238_REG_SRC_PDO_18V;
|
|
break;
|
|
case 20:
|
|
reg = HUB238_REG_SRC_PDO_20V;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
uint8_t temp = 0;
|
|
if (I2CBB2::Mem_Read(HUB238_ADDR, reg, &temp, 1) == true) {
|
|
if (temp & HUB238_PDO_DETECTED) {
|
|
return pdo_slot_to_currentx100(temp);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
uint8_t findBestPDO() {
|
|
uint8_t temp = 0;
|
|
uint16_t ilim = 0;
|
|
uint16_t minimumx10current = 0;
|
|
#if USB_PD_VMAX >= 20
|
|
ilim = hub238_getVoltagePDOCurrent(20);
|
|
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(200);
|
|
if (ilim != 0 && ilim / 10 >= minimumx10current) {
|
|
powerSupplyWattageLimit = ((20 * ilim) / 100) - 2; // We take off 2W for safety of overhead
|
|
return 0b1010;
|
|
}
|
|
#endif
|
|
#if USB_PD_VMAX >= 18
|
|
ilim = hub238_getVoltagePDOCurrent(18);
|
|
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(180);
|
|
if (ilim != 0 && ilim / 10 >= minimumx10current) {
|
|
powerSupplyWattageLimit = ((18 * ilim) / 100) - 2; // We take off 2W for safety of overhead
|
|
return 0b1001;
|
|
}
|
|
#endif
|
|
#if USB_PD_VMAX >= 15
|
|
ilim = hub238_getVoltagePDOCurrent(15);
|
|
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(150);
|
|
if (ilim != 0 && ilim / 10 >= minimumx10current) {
|
|
powerSupplyWattageLimit = ((15 * ilim) / 100) - 2; // We take off 2W for safety of overhead
|
|
return 0b1000;
|
|
}
|
|
#endif
|
|
#if USB_PD_VMAX >= 12
|
|
ilim = hub238_getVoltagePDOCurrent(12);
|
|
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(120);
|
|
if (ilim != 0 && (ilim / 10) >= minimumx10current) {
|
|
powerSupplyWattageLimit = ((12 * ilim) / 100) - 2; // We take off 2W for safety of overhead
|
|
return 0b0011;
|
|
}
|
|
#endif
|
|
#if USB_PD_VMAX >= 9
|
|
ilim = hub238_getVoltagePDOCurrent(9);
|
|
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(90);
|
|
if (ilim != 0 && ilim / 10 >= minimumx10current) {
|
|
powerSupplyWattageLimit = ((9 * ilim) / 100) - 2; // We take off 2W for safety of overhead
|
|
return 0b0010;
|
|
}
|
|
#endif
|
|
|
|
powerSupplyWattageLimit = 10;
|
|
return 0b0001; // 5V PDO
|
|
}
|
|
volatile uint8_t haveSelected = 0xFF;
|
|
|
|
void hub238_check_negotiation() {
|
|
// Dont do anything for first 2 seconds as its internal state machine corrupts if we ask it to change too fast
|
|
|
|
if (xTaskGetTickCount() < 2000) {
|
|
return;
|
|
}
|
|
// Want to check if there is a better PDO to be using
|
|
// First, exit early if we already have changed _or_ no PD
|
|
// Even if it negotiates the same voltage as we want, we still re-run it as that makes it ignore the resistor
|
|
// and instead ask for max amps
|
|
if (haveSelected != 0xFF || !hub238_has_negotiated() || hub238_source_voltage() == 0) {
|
|
return;
|
|
}
|
|
uint8_t currentPDO = 0;
|
|
vTaskDelay(5);
|
|
|
|
uint8_t bestPDO = findBestPDO();
|
|
|
|
if (I2CBB2::Mem_Read(HUB238_ADDR, HUB238_REG_SRC_PDO, ¤tPDO, 1) == true) {
|
|
currentPDO >>= 4; // grab upper bits
|
|
if (currentPDO == bestPDO) {
|
|
haveSelected = bestPDO;
|
|
return;
|
|
}
|
|
currentPDO = bestPDO << 4;
|
|
if (I2CBB2::Mem_Write(HUB238_ADDR, HUB238_REG_SRC_PDO, ¤tPDO, 1) == true) {
|
|
|
|
currentPDO = 0x01; // request for new PDO
|
|
if (I2CBB2::Mem_Write(HUB238_ADDR, HUB238_REG_GO_COMMAND, ¤tPDO, 1) == true) {
|
|
haveSelected = bestPDO;
|
|
vTaskDelay(50);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bool hub238_has_run_selection() { return haveSelected != 0xFF; }
|
|
|
|
bool hub238_has_negotiated() {
|
|
uint8_t temp = 0;
|
|
if (I2CBB2::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS1, &temp, 1) == true) {
|
|
temp >>= 3;
|
|
return (temp & 0b111) == 0b001; // success
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Return selected source voltage in V
|
|
uint16_t hub238_source_voltage() {
|
|
uint8_t temp = 0;
|
|
if (I2CBB2::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS0, &temp, 1) == true) {
|
|
temp >>= 4;
|
|
switch (temp) {
|
|
case 0b0001:
|
|
return 5;
|
|
case 0b0010:
|
|
return 9;
|
|
case 0b0011:
|
|
return 12;
|
|
case 0b0100:
|
|
return 15;
|
|
case 0b0101:
|
|
return 18;
|
|
case 0b0110:
|
|
return 20;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
// Return selected source current in Amps * 100
|
|
uint8_t hub238_source_currentX100() {
|
|
uint8_t temp = 0;
|
|
if (I2CBB2::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS0, &temp, 1) == true) {
|
|
temp &= 0b1111;
|
|
return pdo_slot_to_currentx100(temp);
|
|
}
|
|
return 10; // Failsafe to 0.1 amp
|
|
}
|
|
#endif
|