diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp index ae65dbe13..ebb26ec2c 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp @@ -33,6 +33,7 @@ namespace ams::powctl { }; enum ChargeCurrentState { + ChargeCurrentState_Unknown = 0x0, ChargeCurrentState_NotCharging = 0x1, ChargeCurrentState_ChargingForce20Percent = 0x2, ChargeCurrentState_Charging = 0x3, diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_battery_driver.cpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_battery_driver.cpp new file mode 100644 index 000000000..2e3b6dd00 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_battery_driver.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "powctl_battery_driver.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + /* Generic API. */ + void BatteryDriver::InitializeDriver() { + /* TODO */ + AMS_ABORT(); + } + + void BatteryDriver::FinalizeDriver() { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetDeviceSystemEvent(os::SystemEventType **out, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + /* Check that we support event handlers. */ + R_UNLESS(this->IsEventHandlerEnabled(), powctl::ResultNotAvailable()); + + *out = device->SafeCastTo().GetSystemEvent(); + return ResultSuccess(); + } + + Result BatteryDriver::SetDeviceInterruptEnabled(IDevice *device, bool enable) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + /* Set the interrupt enable. */ + device->SafeCastTo().SetInterruptEnabled(enable); + + return ResultSuccess(); + } + + Result BatteryDriver::GetDeviceErrorStatus(u32 *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetDeviceErrorStatus(IDevice *device, u32 status) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatterySocRep(float *out_percent, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatterySocVf(float *out_percent, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryFullCapacity(int *out_mah, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryRemainingCapacity(int *out_mah, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryPercentageFullThreshold(IDevice *device, float percentage) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryAverageCurrent(int *out_ma, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryCurrent(int *out_ma, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryNeedToRestoreParameters(bool *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryNeedToRestoreParameters(IDevice *device, bool en) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryI2cShutdownEnabled(IDevice *device, bool en) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::IsBatteryPresent(bool *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryCycles(int *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryCycles(IDevice *device, int cycles) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryAge(float *out_percent, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryTemperature(float *out_c, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryMaximumTemperature(float *out_c, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryVCell(int *out_mv, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryAverageVCell(int *out_mv, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryVoltageMinimumAlertThreshold(IDevice *device, int mv) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::GetBatteryOpenCircuitVoltage(int *out_mv, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result BatteryDriver::SetBatteryVoltageMaximumAlertThreshold(IDevice *device, int mv) { + /* TODO */ + AMS_ABORT(); + } + +} diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_battery_driver.hpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_battery_driver.hpp new file mode 100644 index 000000000..6e327cd29 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_battery_driver.hpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "../../powctl_i_power_control_driver.hpp" +#include "powctl_interrupt_event_handler.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + class BatteryDevice : public powctl::impl::IDevice { + NON_COPYABLE(BatteryDevice); + NON_MOVEABLE(BatteryDevice); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::board::nintendo_nx::BatteryDevice, ::ams::powctl::impl::IDevice); + private: + bool use_event_handler; + std::optional event_handler; + os::SystemEventType system_event; + public: + BatteryDevice(bool ev); + + os::SystemEventType *GetSystemEvent() { return std::addressof(this->system_event); } + + void SetInterruptEnabled(bool en) { + if (this->use_event_handler) { + this->event_handler->SetInterruptEnabled(en); + } + } + }; + + class BatteryDriver : public IPowerControlDriver { + NON_COPYABLE(BatteryDriver); + NON_MOVEABLE(BatteryDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::board::nintendo_nx::BatteryDriver, ::ams::powctl::impl::IPowerControlDriver); + public: + BatteryDriver(bool ev) : IPowerControlDriver(ev) { /* ... */ } + + /* Generic API. */ + virtual void InitializeDriver() override; + virtual void FinalizeDriver() override; + + virtual Result GetDeviceSystemEvent(os::SystemEventType **out, IDevice *device) override; + virtual Result SetDeviceInterruptEnabled(IDevice *device, bool enable) override; + + virtual Result GetDeviceErrorStatus(u32 *out, IDevice *device) override; + virtual Result SetDeviceErrorStatus(IDevice *device, u32 status) override; + + /* Battery API. */ + virtual Result GetBatterySocRep(float *out_percent, IDevice *device) override; + + virtual Result GetBatterySocVf(float *out_percent, IDevice *device) override; + + virtual Result GetBatteryFullCapacity(int *out_mah, IDevice *device) override; + virtual Result GetBatteryRemainingCapacity(int *out_mah, IDevice *device) override; + + virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) override; + virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) override; + virtual Result SetBatteryPercentageFullThreshold(IDevice *device, float percentage) override; + + virtual Result GetBatteryAverageCurrent(int *out_ma, IDevice *device) override; + virtual Result GetBatteryCurrent(int *out_ma, IDevice *device) override; + + virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) override; + virtual Result SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) override; + + virtual Result GetBatteryNeedToRestoreParameters(bool *out, IDevice *device) override; + virtual Result SetBatteryNeedToRestoreParameters(IDevice *device, bool en) override; + + virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) override; + virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) override; + + virtual Result IsBatteryPresent(bool *out, IDevice *device) override; + + virtual Result GetBatteryCycles(int *out, IDevice *device) override; + virtual Result SetBatteryCycles(IDevice *device, int cycles) override; + + virtual Result GetBatteryAge(float *out_percent, IDevice *device) override; + + virtual Result GetBatteryTemperature(float *out_c, IDevice *device) override; + virtual Result GetBatteryMaximumTemperature(float *out_c, IDevice *device) override; + + virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) override; + virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) override; + + virtual Result GetBatteryVCell(int *out_mv, IDevice *device) override; + virtual Result GetBatteryAverageVCell(int *out_mv, IDevice *device) override; + + virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) override; + + virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, int mv) override; + + virtual Result GetBatteryOpenCircuitVoltage(int *out_mv, IDevice *device) override; + + virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, int mv) override; + + /* Unsupported Charger API. */ + virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerFastChargeCurrentLimit(int *out_ma, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, int ma) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerChargeVoltageLimit(int *out_mv, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerChargeVoltageLimit(IDevice *device, int mv) override { return powctl::ResultNotSupported(); } + + virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) override { return powctl::ResultNotSupported(); } + + virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerHiZEnabled(IDevice *device, bool en) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerInputCurrentLimit(int *out_ma, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerInputCurrentLimit(IDevice *device, int ma) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerInputVoltageLimit(int *out_mv, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerInputVoltageLimit(IDevice *device, int mv) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) override { return powctl::ResultNotSupported(); } + + virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) override { return powctl::ResultNotSupported(); } + virtual Result ResetChargerWatchdogTimer(IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerBatteryCompensation(int *out_mo, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerBatteryCompensation(IDevice *device, int mo) override { return powctl::ResultNotSupported(); } + + virtual Result GetChargerVoltageClamp(int *out_mv, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetChargerVoltageClamp(IDevice *device, int mv) override { return powctl::ResultNotSupported(); } + }; + +} diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.cpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.cpp index 0339ca6d9..4c8114312 100644 --- a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.cpp +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.cpp @@ -14,13 +14,39 @@ * along with this program. If not, see . */ #include +#include "../../powctl_device_management.hpp" #include "powctl_board_impl.hpp" +#include "powctl_battery_driver.hpp" +#include "powctl_charger_driver.hpp" namespace ams::powctl::impl::board::nintendo_nx { + namespace { + + constinit std::optional g_charger_driver; + constinit std::optional g_battery_driver; + + void InitializeChargerDriver(bool use_event_handlers) { + /* Create the charger driver. */ + g_charger_driver.emplace(use_event_handlers); + + /* Register the driver. */ + powctl::impl::RegisterDriver(std::addressof(*g_charger_driver)); + } + + void InitializeBatteryDriver(bool use_event_handlers) { + /* Create the battery driver. */ + g_battery_driver.emplace(use_event_handlers); + + /* Register the driver. */ + powctl::impl::RegisterDriver(std::addressof(*g_battery_driver)); + } + + } + void Initialize(bool use_event_handlers) { - /* TODO */ - AMS_ABORT(); + InitializeChargerDriver(use_event_handlers); + InitializeBatteryDriver(use_event_handlers); } void Finalize() { diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_bq24193_driver.hpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_bq24193_driver.hpp new file mode 100644 index 000000000..655a4de46 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_bq24193_driver.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::powctl::impl::board::nintendo_nx { + + namespace bq24193 { + + enum ChargerConfiguration { + ChargerConfiguration_ChargeDisable = 0, + ChargerConfiguration_ChargeBattery = 1, + ChargerConfiguration_Otg = 2, + }; + + enum ChargerStatus { + ChargerStatus_NotCharging = 0, + ChargerStatus_PreCharge = 1, + ChargerStatus_FastCharging = 2, + ChargerStatus_ChargeTerminationDone = 3, + }; + + } + + class Bq24193Driver { + private: + os::SdkMutex mutex; + int init_count; + i2c::I2cSession i2c_session; + private: + Result InitializeSession(); + public: + Bq24193Driver() : mutex(), init_count(0), i2c_session() { + /* ... */ + } + + void Initialize() { + std::scoped_lock lk(this->mutex); + R_ABORT_UNLESS(this->InitializeSession()); + } + + Result GetForce20PercentChargeCurrent(bool *out); + Result SetForce20PercentChargeCurrent(bool en); + + Result GetFastChargeCurrentLimit(int *out_ma); + Result SetFastChargeCurrentLimit(int ma); + + Result GetChargeVoltageLimit(int *out_mv); + Result SetChargeVoltageLimit(int mv); + + Result SetChargerConfiguration(bq24193::ChargerConfiguration cfg); + + Result IsHiZEnabled(bool *out); + Result SetHiZEnabled(bool en); + + Result GetInputCurrentLimit(int *out_ma); + Result SetInputCurrentLimit(int ma); + + Result GetInputVoltageLimit(int *out_mv); + Result SetInputVoltageLimit(int mv); + + Result GetChargerStatus(bq24193::ChargerStatus *out); + + Result ResetWatchdogTimer(); + Result SetWatchdogTimerSetting(int seconds); + + Result GetBatteryCompensation(int *out_mo); + Result SetBatteryCompensation(int mo); + + Result GetVoltageClamp(int *out_mv); + Result SetVoltageClamp(int mv); + }; + +} diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_charger_driver.cpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_charger_driver.cpp new file mode 100644 index 000000000..71ddd59b1 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_charger_driver.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "../../powctl_device_management.hpp" +#include "powctl_retry_helper.hpp" +#include "powctl_charger_driver.hpp" +#include "powctl_bq24193_driver.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + namespace { + + constinit std::optional g_charger_device; + + Bq24193Driver &GetBq24193Driver() { + static Bq24193Driver s_bq24193_driver; + return s_bq24193_driver; + } + + } + + /* Generic API. */ + void ChargerDriver::InitializeDriver() { + /* Initialize Bq24193Driver */ + GetBq24193Driver().Initialize(); + + /* Initialize gpio library. */ + gpio::Initialize(); + + /* Create charger device. */ + g_charger_device.emplace(this->IsEventHandlerEnabled()); + + /* Open the device's gpio session. */ + R_ABORT_UNLESS(gpio::OpenSession(g_charger_device->GetPadSession(), gpio::DeviceCode_BattChgEnableN)); + + /* Configure the gpio session as output. */ + gpio::SetDirection(g_charger_device->GetPadSession(), gpio::Direction_Output); + + /* Register our device. */ + this->RegisterDevice(std::addressof(*g_charger_device)); + + /* Register the charger device's code. */ + R_ABORT_UNLESS(powctl::impl::RegisterDeviceCode(powctl::DeviceCode_Bq24193, std::addressof(*g_charger_device))); + } + + void ChargerDriver::FinalizeDriver() { + /* Unregister the charger device code. */ + powctl::impl::UnregisterDeviceCode(powctl::DeviceCode_Bq24193); + + /* Unregister our device. */ + this->UnregisterDevice(std::addressof(*g_charger_device)); + + /* Close the device's gpio session. */ + gpio::CloseSession(g_charger_device->GetPadSession()); + + /* Destroy the charger device. */ + g_charger_device = std::nullopt; + } + + Result ChargerDriver::GetDeviceSystemEvent(os::SystemEventType **out, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + /* Check that we support event handlers. */ + R_UNLESS(this->IsEventHandlerEnabled(), powctl::ResultNotAvailable()); + + *out = device->SafeCastTo().GetSystemEvent(); + return ResultSuccess(); + } + + Result ChargerDriver::SetDeviceInterruptEnabled(IDevice *device, bool enable) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + /* Set the interrupt enable. */ + device->SafeCastTo().SetInterruptEnabled(enable); + + return ResultSuccess(); + } + + Result ChargerDriver::GetDeviceErrorStatus(u32 *out, IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + Result ChargerDriver::SetDeviceErrorStatus(IDevice *device, u32 status) { + /* TODO */ + AMS_ABORT(); + } + + /* Charger API. */ + Result ChargerDriver::GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + /* Check if we're not charging. */ + if (gpio::GetValue(device->SafeCastTo().GetPadSession()) == gpio::GpioValue_High) { + *out = ChargeCurrentState_NotCharging; + } else { + /* Get force 20 percent charge state. */ + bool force_20_percent; + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetForce20PercentChargeCurrent(std::addressof(force_20_percent))); + + /* Set output appropriately. */ + if (force_20_percent) { + *out = ChargeCurrentState_ChargingForce20Percent; + } else { + *out = ChargeCurrentState_Charging; + } + } + + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + switch (state) { + case ChargeCurrentState_NotCharging: + gpio::SetValue(device->SafeCastTo().GetPadSession(), gpio::GpioValue_High); + break; + case ChargeCurrentState_ChargingForce20Percent: + case ChargeCurrentState_Charging: + gpio::SetValue(device->SafeCastTo().GetPadSession(), gpio::GpioValue_Low); + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetForce20PercentChargeCurrent(state == ChargeCurrentState_ChargingForce20Percent)); + break; + case ChargeCurrentState_Unknown: + return powctl::ResultInvalidArgument(); + } + + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerFastChargeCurrentLimit(int *out_ma, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out_ma != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetFastChargeCurrentLimit(out_ma)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerFastChargeCurrentLimit(IDevice *device, int ma) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetFastChargeCurrentLimit(ma)); + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerChargeVoltageLimit(int *out_mv, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out_mv != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetChargeVoltageLimit(out_mv)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerChargeVoltageLimit(IDevice *device, int mv) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetChargeVoltageLimit(mv)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + bq24193::ChargerConfiguration bq_cfg; + switch (cfg) { + case ChargerConfiguration_ChargeDisable: bq_cfg = bq24193::ChargerConfiguration_ChargeDisable; break; + case ChargerConfiguration_ChargeBattery: bq_cfg = bq24193::ChargerConfiguration_ChargeBattery; break; + case ChargerConfiguration_Otg: bq_cfg = bq24193::ChargerConfiguration_Otg; break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetChargerConfiguration(bq_cfg)); + return ResultSuccess(); + } + + Result ChargerDriver::IsChargerHiZEnabled(bool *out, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().IsHiZEnabled(out)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerHiZEnabled(IDevice *device, bool en) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetHiZEnabled(en)); + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerInputCurrentLimit(int *out_ma, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out_ma != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetInputCurrentLimit(out_ma)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerInputCurrentLimit(IDevice *device, int ma) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetInputCurrentLimit(ma)); + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerInputVoltageLimit(int *out_mv, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out_mv != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetInputVoltageLimit(out_mv)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerInputVoltageLimit(IDevice *device, int mv) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetInputVoltageLimit(mv)); + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerChargerStatus(ChargerStatus *out, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + bq24193::ChargerStatus bq_status; + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetChargerStatus(std::addressof(bq_status))); + + switch (bq_status) { + case bq24193::ChargerStatus_NotCharging: + *out = ChargerStatus_NotCharging; + break; + case bq24193::ChargerStatus_PreCharge: + case bq24193::ChargerStatus_FastCharging: + *out = ChargerStatus_Charging; + break; + case bq24193::ChargerStatus_ChargeTerminationDone: + *out = ChargerStatus_ChargeTerminationDone; + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + return ResultSuccess(); + } + + Result ChargerDriver::IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + *out = device->SafeCastTo().IsWatchdogTimerEnabled(); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerWatchdogTimerEnabled(IDevice *device, bool en) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + auto &charger_device = device->SafeCastTo(); + + if (en) { + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().ResetWatchdogTimer()); + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetWatchdogTimerSetting(charger_device.GetWatchdogTimerTimeout().GetSeconds())); + } else { + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetWatchdogTimerSetting(0)); + } + + charger_device.SetWatchdogTimerEnabled(en); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + device->SafeCastTo().SetWatchdogTimerTimeout(timeout); + return ResultSuccess(); + } + + Result ChargerDriver::ResetChargerWatchdogTimer(IDevice *device) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().ResetWatchdogTimer()); + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerBatteryCompensation(int *out_mo, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out_mo != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetBatteryCompensation(out_mo)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerBatteryCompensation(IDevice *device, int mo) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetBatteryCompensation(mo)); + return ResultSuccess(); + } + + Result ChargerDriver::GetChargerVoltageClamp(int *out_mv, IDevice *device) { + /* Validate arguments. */ + R_UNLESS(out_mv != nullptr, powctl::ResultInvalidArgument()); + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().GetVoltageClamp(out_mv)); + return ResultSuccess(); + } + + Result ChargerDriver::SetChargerVoltageClamp(IDevice *device, int mv) { + /* Validate arguments. */ + R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); + + AMS_POWCTL_R_TRY_WITH_RETRY(GetBq24193Driver().SetVoltageClamp(mv)); + return ResultSuccess(); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_charger_driver.hpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_charger_driver.hpp new file mode 100644 index 000000000..69a4814f0 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_charger_driver.hpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "../../powctl_i_power_control_driver.hpp" +#include "powctl_interrupt_event_handler.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + class ChargerDevice : public powctl::impl::IDevice { + NON_COPYABLE(ChargerDevice); + NON_MOVEABLE(ChargerDevice); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::board::nintendo_nx::ChargerDevice, ::ams::powctl::impl::IDevice); + private: + gpio::GpioPadSession gpio_pad_session; + bool watchdog_timer_enabled; + TimeSpan watchdog_timer_timeout; + bool use_event_handler; + std::optional event_handler; + os::SystemEventType system_event; + public: + ChargerDevice(bool ev); + + bool IsWatchdogTimerEnabled() const { return this->watchdog_timer_enabled; } + void SetWatchdogTimerEnabled(bool en) { this->watchdog_timer_enabled = en; } + + TimeSpan GetWatchdogTimerTimeout() const { return this->watchdog_timer_timeout; } + void SetWatchdogTimerTimeout(TimeSpan ts) { this->watchdog_timer_timeout = ts; } + + gpio::GpioPadSession *GetPadSession() { return std::addressof(this->gpio_pad_session); } + + os::SystemEventType *GetSystemEvent() { return std::addressof(this->system_event); } + + void SetInterruptEnabled(bool en) { + if (this->use_event_handler) { + this->event_handler->SetInterruptEnabled(en); + } + } + }; + + class ChargerDriver : public IPowerControlDriver { + NON_COPYABLE(ChargerDriver); + NON_MOVEABLE(ChargerDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::board::nintendo_nx::ChargerDriver, ::ams::powctl::impl::IPowerControlDriver); + public: + ChargerDriver(bool ev) : IPowerControlDriver(ev) { /* ... */ } + + /* Generic API. */ + virtual void InitializeDriver() override; + virtual void FinalizeDriver() override; + + virtual Result GetDeviceSystemEvent(os::SystemEventType **out, IDevice *device) override; + virtual Result SetDeviceInterruptEnabled(IDevice *device, bool enable) override; + + virtual Result GetDeviceErrorStatus(u32 *out, IDevice *device) override; + virtual Result SetDeviceErrorStatus(IDevice *device, u32 status) override; + + /* Charger API. */ + virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) override; + virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) override; + + virtual Result GetChargerFastChargeCurrentLimit(int *out_ma, IDevice *device) override; + virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, int ma) override; + + virtual Result GetChargerChargeVoltageLimit(int *out_mv, IDevice *device) override; + virtual Result SetChargerChargeVoltageLimit(IDevice *device, int mv) override; + + virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) override; + + virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) override; + virtual Result SetChargerHiZEnabled(IDevice *device, bool en) override; + + virtual Result GetChargerInputCurrentLimit(int *out_ma, IDevice *device) override; + virtual Result SetChargerInputCurrentLimit(IDevice *device, int ma) override; + + virtual Result GetChargerInputVoltageLimit(int *out_mv, IDevice *device) override; + virtual Result SetChargerInputVoltageLimit(IDevice *device, int mv) override; + + virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) override; + + virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) override; + virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) override; + + virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) override; + virtual Result ResetChargerWatchdogTimer(IDevice *device) override; + + virtual Result GetChargerBatteryCompensation(int *out_mo, IDevice *device) override; + virtual Result SetChargerBatteryCompensation(IDevice *device, int mo) override; + + virtual Result GetChargerVoltageClamp(int *out_mv, IDevice *device) override; + virtual Result SetChargerVoltageClamp(IDevice *device, int mv) override; + + /* Unsupported Battery API. */ + virtual Result GetBatterySocRep(float *out_percent, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatterySocVf(float *out_percent, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryFullCapacity(int *out_mah, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result GetBatteryRemainingCapacity(int *out_mah, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryPercentageFullThreshold(IDevice *device, float percentage) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryAverageCurrent(int *out_ma, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result GetBatteryCurrent(int *out_ma, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryNeedToRestoreParameters(bool *out, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryNeedToRestoreParameters(IDevice *device, bool en) override { return powctl::ResultNotSupported(); } + + virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) override { return powctl::ResultNotSupported(); } + + virtual Result IsBatteryPresent(bool *out, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryCycles(int *out, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryCycles(IDevice *device, int cycles) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryAge(float *out_percent, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryTemperature(float *out_c, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result GetBatteryMaximumTemperature(float *out_c, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) override { return powctl::ResultNotSupported(); } + virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryVCell(int *out_mv, IDevice *device) override { return powctl::ResultNotSupported(); } + virtual Result GetBatteryAverageVCell(int *out_mv, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, int mv) override { return powctl::ResultNotSupported(); } + + virtual Result GetBatteryOpenCircuitVoltage(int *out_mv, IDevice *device) override { return powctl::ResultNotSupported(); } + + virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, int mv) override { return powctl::ResultNotSupported(); } + }; + +} diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.hpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.hpp index 331c6465e..17c83bb9a 100644 --- a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.hpp +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.hpp @@ -39,6 +39,12 @@ namespace ams::powctl::impl::board::nintendo_nx { return std::addressof(this->gpio_system_event); } + void SetInterruptEnabled(bool en) { + std::scoped_lock lk(this->mutex); + + gpio::SetInterruptEnable(std::addressof(this->gpio_session), en); + } + virtual void HandleEvent() override final { /* Acquire exclusive access to ourselves. */ std::scoped_lock lk(this->mutex); @@ -50,7 +56,7 @@ namespace ams::powctl::impl::board::nintendo_nx { os::ClearSystemEvent(std::addressof(this->gpio_system_event)); /* Signal the event. */ - Derived::SignalEvent(this->device); + static_cast(this)->SignalEvent(this->device); } }; diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp index fc4e1ee55..030443e44 100644 --- a/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp +++ b/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp @@ -44,7 +44,7 @@ namespace ams::powctl::impl { virtual void InitializeDriver() = 0; virtual void FinalizeDriver() = 0; - virtual Result GetDeviceSystemEvent(IDevice *device) = 0; + virtual Result GetDeviceSystemEvent(os::SystemEventType **out, IDevice *device) = 0; virtual Result SetDeviceInterruptEnabled(IDevice *device, bool enable) = 0; /* TODO: Eventually implement proper error status enum? */