- sys-clk-OC: Charging current limit

This commit is contained in:
KazushiM
2023-01-02 16:12:13 +08:00
parent 139c7dfcad
commit 277f8d48e5
14 changed files with 270 additions and 135 deletions

View File

@@ -19,6 +19,7 @@ extern "C" {
#include "sysclk/apm.h"
#include "sysclk/config.h"
#include "sysclk/errors.h"
#include "sysclk/i2c.h"
#include "sysclk/psm_ext.h"
#ifdef __cplusplus

View File

@@ -20,7 +20,7 @@ typedef enum {
SysClkConfigValue_AutoCPUBoost,
SysClkConfigValue_SyncReverseNXMode,
SysClkConfigValue_AllowUnsafeFrequencies,
SysClkConfigValue_DisableFastCharging,
SysClkConfigValue_ChargingCurrentLimit,
SysClkConfigValue_ChargingLimitPercentage,
SysClkConfigValue_GovernorExperimental,
SysClkConfigValue_EnumMax,
@@ -46,8 +46,8 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
return pretty ? "Sync ReverseNX Mode Sync" : "sync_reversenx_mode";
case SysClkConfigValue_AllowUnsafeFrequencies:
return pretty ? "Allow Unsafe Frequencies" : "allow_unsafe_freq";
case SysClkConfigValue_DisableFastCharging:
return pretty ? "Disable Fast Charging" : "disable_fast_charging";
case SysClkConfigValue_ChargingCurrentLimit:
return pretty ? "Charging Current Limit (mA)" : "charging_current";
case SysClkConfigValue_ChargingLimitPercentage:
return pretty ? "Charging Limit (%%)" : "charging_limit_perc";
case SysClkConfigValue_GovernorExperimental:
@@ -66,12 +66,13 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
case SysClkConfigValue_AllowUnsafeFrequencies:
case SysClkConfigValue_DisableFastCharging:
case SysClkConfigValue_GovernorExperimental:
return 0ULL;
case SysClkConfigValue_AutoCPUBoost:
case SysClkConfigValue_SyncReverseNXMode:
return 1ULL;
case SysClkConfigValue_ChargingCurrentLimit:
return 2000ULL;
case SysClkConfigValue_ChargingLimitPercentage:
return 100ULL;
default:
@@ -91,9 +92,10 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
case SysClkConfigValue_AutoCPUBoost:
case SysClkConfigValue_SyncReverseNXMode:
case SysClkConfigValue_AllowUnsafeFrequencies:
case SysClkConfigValue_DisableFastCharging:
case SysClkConfigValue_GovernorExperimental:
return (input & 0x1) == input;
case SysClkConfigValue_ChargingCurrentLimit:
return (input >= 100 && input <= 2000 && input % 100 == 0);
case SysClkConfigValue_ChargingLimitPercentage:
return (input <= 100 && input >= 20);
default:

View File

@@ -0,0 +1,36 @@
#pragma once
#include <switch.h>
// To use i2c service, sm and i2c should be intialized via smInitialize() and i2cInitialize().
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val);
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out);
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out);
// Max17050 fuel gauge
float I2c_Max17050_GetBatteryCurrent();
const u8 MAX17050_CURRENT_REG = 0x0A;
// Max77812 Mariko-specific buck converter
typedef enum I2c_Max77812_Volt_Type {
I2c_Max77812_CPUVOLT_REG = 0x26,
I2c_Max77812_GPUVOLT_REG = 0x23,
I2c_Max77812_MEMVOLT_REG = 0x25,
} I2c_Max77812_Volt_Type;
u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type);
// Bq24193 Battery management
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw);
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma);
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma);
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma);
const u32 MA_RANGE_MIN = 512;
const u32 MA_RANGE_MAX = 4544;
const u8 BQ24193_CHARGE_CURRENT_CONTROL_REG = 0x2;

View File

@@ -66,12 +66,10 @@ typedef enum {
bool PsmIsChargerConnected(const PsmChargeInfo* info);
bool PsmIsCharging(const PsmChargeInfo* info);
bool PsmIsFastChargingEnabled(const PsmChargeInfo* info);
typedef enum {
PsmBatteryState_Discharging,
PsmBatteryState_ChargingPaused,
PsmBatteryState_SlowCharging,
PsmBatteryState_FastCharging
} PsmBatteryState;

View File

@@ -0,0 +1,150 @@
#include <sysclk/i2c.h>
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val) {
// ams::fatal::srv::StopSoundTask::StopSound()
// I2C Bus Communication Reference: https://www.ti.com/lit/an/slva704/slva704.pdf
struct {
u8 reg;
u8 val;
} __attribute__((packed)) cmd;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
cmd.val = val;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
i2csessionClose(&_session);
return res;
}
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out) {
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u8 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res) {
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
i2csessionClose(&_session);
if (res) {
return res;
}
*out = rec.val;
return 0;
}
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out) {
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u16 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res) {
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
i2csessionClose(&_session);
if (res) {
return res;
}
*out = rec.val;
return 0;
}
float I2c_Max17050_GetBatteryCurrent() {
u16 val;
Result res = I2cRead_OutU16(I2cDevice_Max17050, MAX17050_CURRENT_REG, &val);
if (res)
return 0.f;
const float SenseResistor = 5.; // in uOhm
const float CGain = 1.99993;
return (s16)val * (1.5625 / (SenseResistor * CGain));
}
u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type) {
u8 reg = (u8)type;
const u32 MIN_MV = 250;
const u32 MV_STEP = 5;
const u8 RESET_VAL = 0x78;
u8 val = RESET_VAL;
// Retry 3 times if received RESET_VAL
for (int i = 0; i < 3; i++) {
if (I2cRead_OutU8(I2cDevice_Max77812_2, reg, &val))
return 0u;
if (val != RESET_VAL)
break;
svcSleepThread(10);
}
return val * MV_STEP + MIN_MV;
}
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma) {
// Adjustment is required
u8 raw = 0;
if (ma > MA_RANGE_MAX) // capping
ma = MA_RANGE_MAX;
bool pct20 = ma <= (MA_RANGE_MIN - 64);
if (pct20) {
ma = ma * 5;
raw |= 0x1;
}
ma -= ma % 100; // round to 100
ma -= (MA_RANGE_MIN - 64); // ceiling
raw |= (ma >> 6) << 2;
return raw;
};
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw) {
// No adjustment is allowed
u32 ma = (((raw >> 2)) << 6) + MA_RANGE_MIN;
bool pct20 = raw & 1;
if (pct20)
ma = ma * 20 / 100;
return ma;
};
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma) {
u8 raw;
Result res = I2cRead_OutU8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, &raw);
if (res)
return res;
*ma = I2c_Bq24193_Convert_Raw_mA(raw);
return 0;
}
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma) {
u8 raw = I2c_Bq24193_Convert_mA_Raw(ma);
return I2cSet_U8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, raw);
}

View File

@@ -32,24 +32,19 @@ bool PsmIsCharging(const PsmChargeInfo* info) {
return PsmIsChargerConnected(info) && ((info->unk_x14 >> 8) & 1);
}
bool PsmIsFastChargingEnabled(const PsmChargeInfo* info) {
return info->ChargeCurrentLimit > 768;
}
PsmBatteryState PsmGetBatteryState(const PsmChargeInfo* info) {
if (!PsmIsChargerConnected(info))
return PsmBatteryState_Discharging;
if (!PsmIsCharging(info))
return PsmBatteryState_ChargingPaused;
return PsmIsFastChargingEnabled(info) ? PsmBatteryState_FastCharging : PsmBatteryState_SlowCharging;
return PsmBatteryState_FastCharging;
}
const char* PsmGetBatteryStateIcon(const PsmChargeInfo* info) {
switch (PsmGetBatteryState(info)) {
case PsmBatteryState_Discharging: return "\u25c0"; // ◀
case PsmBatteryState_ChargingPaused:return "| |";
case PsmBatteryState_SlowCharging: return "\u25b6"; // ▶
case PsmBatteryState_FastCharging: return "\u25b6\u25b6"; // ▶▶
case PsmBatteryState_FastCharging: return "\u25b6"; // ▶
default: return "?";
}
}