diff --git a/stratosphere/boot/source/boot_battery_driver.cpp b/stratosphere/boot/source/boot_battery_driver.cpp index a00dca2f5..7416e4789 100644 --- a/stratosphere/boot/source/boot_battery_driver.cpp +++ b/stratosphere/boot/source/boot_battery_driver.cpp @@ -353,4 +353,22 @@ Result BatteryDriver::GetBatteryPercentage(size_t *out) { *out = static_cast(converted_percentage); } return ResultSuccess; +} + +Result BatteryDriver::SetShutdownTimer() { + return this->Write(Max17050ShdnTimer, 0xE000); +} + +Result BatteryDriver::GetShutdownEnabled(bool *out) { + u16 val = 0; + Result rc = this->Read(Max17050Config, &val); + if (R_FAILED(rc)) { + return rc; + } + *out = (val & 0x0040) != 0; + return ResultSuccess; +} + +Result BatteryDriver::SetShutdownEnabled(bool enabled) { + return this->ReadWrite(Max17050Config, 0x0040, enabled ? 0x0040 : 0x0000); } \ No newline at end of file diff --git a/stratosphere/boot/source/boot_battery_driver.hpp b/stratosphere/boot/source/boot_battery_driver.hpp index 8d46d8f9b..fa69afbc8 100644 --- a/stratosphere/boot/source/boot_battery_driver.hpp +++ b/stratosphere/boot/source/boot_battery_driver.hpp @@ -58,4 +58,7 @@ class BatteryDriver { Result GetAverageVCell(u32 *out); Result GetSocRep(double *out); Result GetBatteryPercentage(size_t *out); + Result SetShutdownTimer(); + Result GetShutdownEnabled(bool *out); + Result SetShutdownEnabled(bool enabled); }; diff --git a/stratosphere/boot/source/boot_check_battery.cpp b/stratosphere/boot/source/boot_check_battery.cpp index 720993389..d82c5aeb7 100644 --- a/stratosphere/boot/source/boot_check_battery.cpp +++ b/stratosphere/boot/source/boot_check_battery.cpp @@ -267,7 +267,7 @@ void Boot::CheckBatteryCharge() { pmic_driver.ShutdownSystem(); break; case CheckBatteryResult_Reboot: - pmic_driver.RebootSystem(); + Boot::RebootSystem(); break; default: std::abort(); diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 5f8bd8cdb..945d7e35c 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -25,7 +25,6 @@ #include "boot_functions.hpp" #include "boot_reboot_manager.hpp" -#include "i2c_driver/i2c_api.hpp" extern "C" { extern u32 __start__; diff --git a/stratosphere/boot/source/boot_pmic_driver.cpp b/stratosphere/boot/source/boot_pmic_driver.cpp index 7b3ce2d8e..24c8d6151 100644 --- a/stratosphere/boot/source/boot_pmic_driver.cpp +++ b/stratosphere/boot/source/boot_pmic_driver.cpp @@ -68,6 +68,65 @@ Result PmicDriver::GetPowerButtonPressed(bool *out) { } Result PmicDriver::ShutdownSystem(bool reboot) { - /* TODO: Implement this. */ + const u8 on_off_1_addr = 0x41; + const u8 on_off_2_addr = 0x42; + + /* Get value, set or clear software reset mask. */ + u8 on_off_2_val = 0; + if (R_FAILED(Boot::ReadI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)))) { + std::abort(); + } + if (reboot) { + on_off_2_val |= 0x80; + } else { + on_off_2_val &= ~0x80; + } + if (R_FAILED(Boot::WriteI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)))) { + std::abort(); + } + + /* Get value, set software reset mask. */ + u8 on_off_1_val = 0; + if (R_FAILED(Boot::ReadI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)))) { + std::abort(); + } + on_off_1_val |= 0x80; + + /* Finalize the battery. */ + { + BatteryDriver battery_driver; + this->FinalizeBattery(&battery_driver); + } + + /* Actually write the value to trigger shutdown/reset. */ + if (R_FAILED(Boot::WriteI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)))) { + std::abort(); + } + + /* Allow up to 5 seconds for shutdown/reboot to take place. */ + svcSleepThread(5'000'000'000ul); std::abort(); -} \ No newline at end of file +} + +void PmicDriver::FinalizeBattery(BatteryDriver *battery_driver) { + /* Set shutdown timer. */ + battery_driver->SetShutdownTimer(); + + /* Get whether shutdown is enabled. */ + bool shutdown_enabled; + if (R_FAILED(battery_driver->GetShutdownEnabled(&shutdown_enabled))) { + return; + } + + bool ac_ok; + bool desired_shutdown_enabled; + if (R_FAILED(this->GetAcOk(&ac_ok)) || ac_ok) { + desired_shutdown_enabled = false; + } else { + desired_shutdown_enabled = true; + } + + if (shutdown_enabled != desired_shutdown_enabled) { + battery_driver->SetShutdownEnabled(desired_shutdown_enabled); + } +} diff --git a/stratosphere/boot/source/boot_pmic_driver.hpp b/stratosphere/boot/source/boot_pmic_driver.hpp index cc8f84e90..161fd39b5 100644 --- a/stratosphere/boot/source/boot_pmic_driver.hpp +++ b/stratosphere/boot/source/boot_pmic_driver.hpp @@ -19,6 +19,7 @@ #include #include "i2c_driver/i2c_api.hpp" +#include "boot_battery_driver.hpp" class PmicDriver { private: @@ -36,6 +37,7 @@ class PmicDriver { private: Result GetPowerStatus(u8 *out); Result ShutdownSystem(bool reboot); + void FinalizeBattery(BatteryDriver *battery_driver); public: void ShutdownSystem(); void RebootSystem();