From cd7d7894f1d8e45199862485db7d031b68f0dcb0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 2 Nov 2020 18:13:36 -0800 Subject: [PATCH] powctl: implement client api (needs board-specific impl) --- .../libstratosphere/include/stratosphere.hpp | 1 + .../impl/ams_system_thread_definitions.hpp | 3 + .../stratosphere/ddsf/ddsf_i_castable.hpp | 2 + .../gpio/driver/gpio_i_gpio_driver.hpp | 2 +- .../i2c/driver/i2c_i2c_device_property.hpp | 2 +- .../i2c/driver/i2c_i_i2c_driver.hpp | 2 +- .../include/stratosphere/powctl.hpp | 23 + .../powctl/driver/powctl_driver_api.hpp | 25 + .../powctl/powctl_battery_api.hpp | 70 +++ .../powctl/powctl_charger_api.hpp | 58 +++ .../powctl_devices.board.nintendo_nx.hpp | 29 ++ .../powctl/powctl_select_devices.hpp | 24 + .../powctl/powctl_session_api.hpp | 46 ++ .../stratosphere/powctl/powctl_types.hpp | 41 ++ .../pwm/driver/pwm_i_pwm_device.hpp | 2 +- .../pwm/driver/pwm_i_pwm_driver.hpp | 2 +- .../board/nintendo_nx/powctl_board_impl.cpp | 31 ++ .../board/nintendo_nx/powctl_board_impl.hpp | 26 ++ .../powctl_interrupt_event_handler.cpp | 31 ++ .../powctl_interrupt_event_handler.hpp | 94 ++++ .../board/nintendo_nx/powctl_retry_helper.hpp | 41 ++ .../powctl/impl/powctl_charger_driver.hpp | 136 ++++++ .../powctl/impl/powctl_device_management.cpp | 138 ++++++ .../powctl/impl/powctl_device_management.hpp | 36 ++ .../impl/powctl_i_power_control_driver.hpp | 136 ++++++ .../impl/powctl_select_board_driver.hpp | 32 ++ .../source/powctl/powctl_battery_api.cpp | 439 ++++++++++++++++++ .../source/powctl/powctl_charger_api.cpp | 329 +++++++++++++ .../source/powctl/powctl_driver_api.cpp | 39 ++ .../source/powctl/powctl_session_api.cpp | 89 ++++ .../libvapours/include/vapours/results.hpp | 1 + .../vapours/results/powctl_results.hpp | 28 ++ .../boot/source/boot_driver_management.cpp | 5 + .../boot/source/boot_driver_management.hpp | 1 + stratosphere/boot/source/boot_fan_enable.cpp | 2 +- stratosphere/boot/source/boot_fan_enable.hpp | 2 +- stratosphere/boot/source/boot_main.cpp | 27 +- 37 files changed, 1984 insertions(+), 11 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/powctl.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/driver/powctl_driver_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/powctl_devices.board.nintendo_nx.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/powctl_select_devices.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/powctl_session_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.cpp create mode 100644 libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.cpp create mode 100644 libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_retry_helper.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp create mode 100644 libraries/libstratosphere/source/powctl/impl/powctl_device_management.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp create mode 100644 libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp create mode 100644 libraries/libstratosphere/source/powctl/powctl_battery_api.cpp create mode 100644 libraries/libstratosphere/source/powctl/powctl_charger_api.cpp create mode 100644 libraries/libstratosphere/source/powctl/powctl_driver_api.cpp create mode 100644 libraries/libstratosphere/source/powctl/powctl_session_api.cpp create mode 100644 libraries/libvapours/include/vapours/results/powctl_results.hpp diff --git a/libraries/libstratosphere/include/stratosphere.hpp b/libraries/libstratosphere/include/stratosphere.hpp index a6eb28d13..8b8b105f0 100644 --- a/libraries/libstratosphere/include/stratosphere.hpp +++ b/libraries/libstratosphere/include/stratosphere.hpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp b/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp index 5b755098e..06a1e0269 100644 --- a/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp +++ b/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp @@ -95,6 +95,9 @@ namespace ams::impl { /* bpc. */ AMS_DEFINE_SYSTEM_THREAD(4, bpc, IpcServer); + /* powctl. */ + AMS_DEFINE_SYSTEM_THREAD(9, powctl, InterruptHandler); + /* hid. */ AMS_DEFINE_SYSTEM_THREAD(-10, hid, IpcServer); diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp index 16f467e55..b863c6152 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp @@ -23,6 +23,7 @@ namespace ams::ddsf { #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) #define AMS_DDSF_CASTABLE_TRAITS(__CLASS__, __BASE__) \ + static_assert(std::convertible_to<__CLASS__ *, __BASE__ *>); \ public: \ static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{#__CLASS__, __BASE__::s_ams_ddsf_castable_type_tag}; \ constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; } @@ -30,6 +31,7 @@ namespace ams::ddsf { #else #define AMS_DDSF_CASTABLE_TRAITS(__CLASS__, __BASE__) \ + static_assert(std::convertible_to<__CLASS__ *, __BASE__ *>); \ public: \ static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{__BASE__::s_ams_ddsf_castable_type_tag}; \ constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; } diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp index e9e1ae892..85daec0c8 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp @@ -25,7 +25,7 @@ namespace ams::gpio::driver { class IGpioDriver : public ::ams::ddsf::IDriver { NON_COPYABLE(IGpioDriver); NON_MOVEABLE(IGpioDriver); - AMS_DDSF_CASTABLE_TRAITS(ams::gpio::IGpioDriver, ::ams::ddsf::IDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::IGpioDriver, ::ams::ddsf::IDriver); public: IGpioDriver() : IDriver() { /* ... */ } virtual ~IGpioDriver() { /* ... */ } diff --git a/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i2c_device_property.hpp b/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i2c_device_property.hpp index b7bbeb1aa..42e4efd7f 100644 --- a/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i2c_device_property.hpp +++ b/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i2c_device_property.hpp @@ -23,7 +23,7 @@ namespace ams::i2c::driver { class I2cDeviceProperty : public ::ams::ddsf::IDevice { NON_COPYABLE(I2cDeviceProperty); NON_MOVEABLE(I2cDeviceProperty); - AMS_DDSF_CASTABLE_TRAITS(ams::i2c::I2cDeviceProperty, ::ams::ddsf::IDevice); + AMS_DDSF_CASTABLE_TRAITS(ams::i2c::driver::I2cDeviceProperty, ::ams::ddsf::IDevice); private: u16 address; AddressingMode addressing_mode; diff --git a/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i_i2c_driver.hpp b/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i_i2c_driver.hpp index 867234a54..7afdde3f4 100644 --- a/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i_i2c_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i_i2c_driver.hpp @@ -25,7 +25,7 @@ namespace ams::i2c::driver { class II2cDriver : public ::ams::ddsf::IDriver { NON_COPYABLE(II2cDriver); NON_MOVEABLE(II2cDriver); - AMS_DDSF_CASTABLE_TRAITS(ams::i2c::II2cDriver, ::ams::ddsf::IDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::i2c::driver::II2cDriver, ::ams::ddsf::IDriver); public: II2cDriver() : IDriver() { /* ... */ } virtual ~II2cDriver() { /* ... */ } diff --git a/libraries/libstratosphere/include/stratosphere/powctl.hpp b/libraries/libstratosphere/include/stratosphere/powctl.hpp new file mode 100644 index 000000000..02d421952 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl.hpp @@ -0,0 +1,23 @@ +/* + * 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 +#include +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/powctl_driver_api.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/powctl_driver_api.hpp new file mode 100644 index 000000000..7ed561a78 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/powctl_driver_api.hpp @@ -0,0 +1,25 @@ +/* + * 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 + +namespace ams::powctl { + + void Initialize(bool enable_interrupt_handlers); + void Finalize(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp new file mode 100644 index 000000000..1b74f6fbc --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp @@ -0,0 +1,70 @@ +/* + * 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 +#include + +namespace ams::powctl { + + /* Battery API. */ + Result GetBatterySocRep(float *out_percent, Session &session); + + Result GetBatterySocVf(float *out_percent, Session &session); + + Result GetBatteryFullCapacity(u32 *out_mah, Session &session); + Result GetBatteryRemainingCapacity(u32 *out_mah, Session &session); + + Result SetBatteryPercentageMinimumAlertThreshold(Session &session, float percentage); + Result SetBatteryPercentageMaximumAlertThreshold(Session &session, float percentage); + Result SetBatteryPercentageFullThreshold(Session &session, float percentage); + + Result GetBatteryAverageCurrent(u32 *out_ma, Session &session); + Result GetBatteryCurrent(u32 *out_ma, Session &session); + + Result GetBatteryInternalState(void *dst, size_t *out_size, Session &session, size_t dst_size); + Result SetBatteryInternalState(Session &session, const void *src, size_t src_size); + + Result GetBatteryNeedToRestoreParameters(bool *out, Session &session); + Result SetBatteryNeedToRestoreParameters(Session &session, bool en); + + Result IsBatteryI2cShutdownEnabled(bool *out, Session &session); + Result SetBatteryI2cShutdownEnabled(Session &session, bool en); + + Result IsBatteryRemoved(bool *out, Session &session); + + Result GetBatteryCycles(u32 *out, Session &session); + Result SetBatteryCycles(Session &session, u32 cycles); + + Result GetBatteryAge(float *out_percent, Session &session); + + Result GetBatteryTemperature(float *out_c, Session &session); + Result GetBatteryMaximumTemperature(float *out_c, Session &session); + + Result SetBatteryTemperatureMinimumAlertThreshold(Session &session, float c); + Result SetBatteryTemperatureMaximumAlertThreshold(Session &session, float c); + + Result GetBatteryVCell(u32 *out_mv, Session &session); + Result GetBatteryAverageVCell(u32 *out_mv, Session &session); + + Result GetBatteryAverageVCellTime(TimeSpan *out, Session &session); + + Result GetBatteryOpenCircuitVoltage(u32 *out_mv, Session &session); + + Result SetBatteryVoltageMinimumAlertThreshold(Session &session, u32 mv); + Result SetBatteryVoltageMaximumAlertThreshold(Session &session, u32 mv); + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp new file mode 100644 index 000000000..acc6c1064 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp @@ -0,0 +1,58 @@ +/* + * 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 +#include + +namespace ams::powctl { + + /* Charger API. */ + Result GetChargerChargeCurrentState(ChargeCurrentState *out, Session &session); + Result SetChargerChargeCurrentState(Session &session, ChargeCurrentState state); + + Result GetChargerFastChargeCurrentLimit(u32 *out_ma, Session &session); + Result SetChargerFastChargeCurrentLimit(Session &session, u32 ma); + + Result GetChargerChargeVoltageLimit(u32 *out_mv, Session &session); + Result SetChargerChargeVoltageLimit(Session &session, u32 mv); + + Result SetChargerChargerConfiguration(Session &session, ChargerConfiguration cfg); + + Result IsChargerHiZEnabled(bool *out, Session &session); + Result SetChargerHiZEnabled(Session &session, bool en); + + Result GetChargerInputCurrentLimit(u32 *out_ma, Session &session); + Result SetChargerInputCurrentLimit(Session &session, u32 ma); + + Result GetChargerInputVoltageLimit(u32 *out_mv, Session &session); + Result SetChargerInputVoltageLimit(Session &session, u32 mv); + + Result GetChargerChargerStatus(ChargerStatus *out, Session &session); + + Result IsChargerWatchdogTimerEnabled(bool *out, Session &session); + Result SetChargerWatchdogTimerEnabled(Session &session, bool en); + + Result SetChargerWatchdogTimerTimeout(Session &session, TimeSpan timeout); + Result ResetChargerWatchdogTimer(Session &session); + + Result GetChargerBatteryCompensation(u32 *out_mo, Session &session); + Result SetChargerBatteryCompensation(Session &session, u32 mo); + + Result GetChargerVoltageClamp(u32 *out_mv, Session &session); + Result SetChargerVoltageClamp(Session &session, u32 mv); + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_devices.board.nintendo_nx.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_devices.board.nintendo_nx.hpp new file mode 100644 index 000000000..c2236fbfe --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_devices.board.nintendo_nx.hpp @@ -0,0 +1,29 @@ +/* + * 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 +#include + +namespace ams::powctl { + + /* Fuel Gauge. */ + constexpr inline const DeviceCode DeviceCode_Max17050 = i2c::DeviceCode_Max17050; + + /* Charger. */ + constexpr inline const DeviceCode DeviceCode_Bq24193 = i2c::DeviceCode_Bq24193; + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_select_devices.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_select_devices.hpp new file mode 100644 index 000000000..611312f80 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_select_devices.hpp @@ -0,0 +1,24 @@ +/* + * 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 + +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + #include +#else + /* Error? */ +#endif diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_session_api.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_session_api.hpp new file mode 100644 index 000000000..7c0e3fbd6 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_session_api.hpp @@ -0,0 +1,46 @@ +/* + * 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 + +namespace ams::powctl { + + namespace impl { + + class SessionImpl : public ::ams::ddsf::ISession { + NON_COPYABLE(SessionImpl); + NON_MOVEABLE(SessionImpl); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::SessionImpl, ::ams::ddsf::ISession); + public: + SessionImpl() : ISession() { /* ... */ } + + ~SessionImpl() { ddsf::CloseSession(this); } + }; + + } + + struct Session { + bool has_session; + TYPED_STORAGE(impl::SessionImpl) impl_storage; + + Session() : has_session(false) { /* ... */ } + }; + + Result OpenSession(Session *out, DeviceCode device_code, ddsf::AccessMode access_mode); + void CloseSession(Session &session); + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp b/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp new file mode 100644 index 000000000..3a3538bb9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp @@ -0,0 +1,41 @@ +/* + * 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 { + + /* Charger types. */ + enum ChargerStatus { + ChargerStatus_Charging = 1, + + ChargerStatus_NotCharging = 3, + ChargerStatus_ChargeTerminationDone = 4, + }; + + enum ChargerConfiguration { + ChargerConfiguration_ChargeDisable = 0, + ChargerConfiguration_ChargeBattery = 1, + ChargerConfiguration_Otg = 2, + }; + + enum ChargeCurrentState { + ChargeCurrentState_NotCharging = 0x1, + ChargeCurrentState_ChargingForce20Percent = 0x2, + ChargeCurrentState_Charging = 0x3, + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_device.hpp b/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_device.hpp index 6949c7cfb..74d41bdcc 100644 --- a/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_device.hpp +++ b/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_device.hpp @@ -23,7 +23,7 @@ namespace ams::pwm::driver { class IPwmDevice : public ::ams::ddsf::IDevice { NON_COPYABLE(IPwmDevice); NON_MOVEABLE(IPwmDevice); - AMS_DDSF_CASTABLE_TRAITS(ams::pwm::IPwmDevice, ::ams::ddsf::IDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::pwm::driver::IPwmDevice, ::ams::ddsf::IDevice); private: int channel_index; public: diff --git a/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_driver.hpp b/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_driver.hpp index 11f8dd601..355359758 100644 --- a/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_driver.hpp @@ -24,7 +24,7 @@ namespace ams::pwm::driver { class IPwmDriver : public ::ams::ddsf::IDriver { NON_COPYABLE(IPwmDriver); NON_MOVEABLE(IPwmDriver); - AMS_DDSF_CASTABLE_TRAITS(ams::pwm::IPwmDriver, ::ams::ddsf::IDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::pwm::driver::IPwmDriver, ::ams::ddsf::IDriver); public: IPwmDriver() : IDriver() { /* ... */ } virtual ~IPwmDriver() { /* ... */ } 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 new file mode 100644 index 000000000..0339ca6d9 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.cpp @@ -0,0 +1,31 @@ +/* + * 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_board_impl.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + void Initialize(bool use_event_handlers) { + /* TODO */ + AMS_ABORT(); + } + + void Finalize() { + /* TODO */ + AMS_ABORT(); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.hpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.hpp new file mode 100644 index 000000000..902c5e99f --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_board_impl.hpp @@ -0,0 +1,26 @@ +/* + * 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_interrupt_event_handler.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + void Initialize(bool use_event_handlers); + void Finalize(); + +} diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.cpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.cpp new file mode 100644 index 000000000..360abece6 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.cpp @@ -0,0 +1,31 @@ +/* + * 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_interrupt_event_handler.hpp" + +namespace ams::powctl::impl::board::nintendo_nx { + + void ChargerInterruptEventHandler::SignalEvent(IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + + void BatteryInterruptEventHandler::SignalEvent(IDevice *device) { + /* TODO */ + AMS_ABORT(); + } + +} \ No newline at end of file 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 new file mode 100644 index 000000000..331c6465e --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_interrupt_event_handler.hpp @@ -0,0 +1,94 @@ +/* + * 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" + +namespace ams::powctl::impl::board::nintendo_nx { + + template + class InterruptEventHandler : public ddsf::IEventHandler { + private: + IDevice *device; + gpio::GpioPadSession gpio_session; + os::SystemEventType gpio_system_event; + os::SdkMutex mutex; + public: + InterruptEventHandler(IDevice *dv) : IEventHandler(), device(dv), mutex() { + /* Initialize the gpio session. */ + Derived::Initialize(std::addressof(this->gpio_session), std::addressof(this->gpio_system_event)); + + /* Initialize ourselves as an event handler. */ + IEventHandler::Initialize(std::addressof(this->gpio_system_event)); + } + + os::SystemEventType *GetSystemEvent() { + return std::addressof(this->gpio_system_event); + } + + virtual void HandleEvent() override final { + /* Acquire exclusive access to ourselves. */ + std::scoped_lock lk(this->mutex); + + /* Clear our interrupt status. */ + gpio::ClearInterruptStatus(std::addressof(this->gpio_session)); + + /* Clear our system event. */ + os::ClearSystemEvent(std::addressof(this->gpio_system_event)); + + /* Signal the event. */ + Derived::SignalEvent(this->device); + } + }; + + class ChargerInterruptEventHandler : public InterruptEventHandler { + friend class InterruptEventHandler; + private: + static void Initialize(gpio::GpioPadSession *session, os::SystemEventType *event) { + /* Open the gpio session. */ + R_ABORT_UNLESS(gpio::OpenSession(session, gpio::DeviceCode_Bq24190Irq)); + + /* Configure the gpio session. */ + gpio::SetDirection(session, gpio::Direction_Input); + gpio::SetInterruptMode(session, gpio::InterruptMode_FallingEdge); + gpio::SetInterruptEnable(session, true); + + /* Bind the interrupt event. */ + R_ABORT_UNLESS(gpio::BindInterrupt(event, session)); + } + + void SignalEvent(IDevice *device); + }; + + class BatteryInterruptEventHandler : public InterruptEventHandler { + friend class InterruptEventHandler; + private: + static void Initialize(gpio::GpioPadSession *session, os::SystemEventType *event) { + /* Open the gpio session. */ + R_ABORT_UNLESS(gpio::OpenSession(session, gpio::DeviceCode_BattMgicIrq)); + + /* Configure the gpio session. */ + gpio::SetDirection(session, gpio::Direction_Input); + gpio::SetInterruptMode(session, gpio::InterruptMode_LowLevel); + + /* Bind the interrupt event. */ + R_ABORT_UNLESS(gpio::BindInterrupt(event, session)); + } + + void SignalEvent(IDevice *device); + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_retry_helper.hpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_retry_helper.hpp new file mode 100644 index 000000000..d43109976 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo_nx/powctl_retry_helper.hpp @@ -0,0 +1,41 @@ +/* + * 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 { + + constexpr inline const TimeSpan PowerControlRetryTimeout = TimeSpan::FromSeconds(10); + constexpr inline const TimeSpan PowerControlRetryInterval = TimeSpan::FromMilliSeconds(20); + + #define AMS_POWCTL_R_TRY_WITH_RETRY(__EXPR__) \ + ({ \ + TimeSpan __powctl_retry_current_time = 0; \ + while (true) { \ + const Result __powctl_retry_result = (__EXPR__); \ + if (R_SUCCEEDED(__powctl_retry_result)) { \ + break; \ + } \ + \ + __powctl_retry_current_time += PowerControlRetryInterval; \ + R_UNLESS(__powctl_retry_current_time < PowerControlRetryTimeout, __powctl_retry_result); \ + \ + os::SleepThread(PowerControlRetryInterval); \ + } \ + }) + + +} diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp new file mode 100644 index 000000000..c9a31a707 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/powctl_charger_driver.hpp @@ -0,0 +1,136 @@ +/* + * 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 { + + class IDevice : public ::ams::ddsf::IDevice { + NON_COPYABLE(IDevice); + NON_MOVEABLE(IDevice); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::IDevice, ::ams::ddsf::IDevice); + public: + IDevice() : ddsf::IDevice(false) { /* ... */ } + virtual ~IDevice() { /* ... */ } + }; + + class IPowerControlDriver : public ::ams::ddsf::IDriver { + NON_COPYABLE(IPowerControlDriver); + NON_MOVEABLE(IPowerControlDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::IPowerControlDriver, ::ams::ddsf::IDriver); + private: + bool event_handler_enabled; + protected: + constexpr bool IsEventHandlerEnabled() const { + return this->event_handler_enabled; + } + public: + IPowerControlDriver(bool ev) : IDriver(), event_handler_enabled(ev) { /* ... */ } + virtual ~IPowerControlDriver() { /* ... */ } + + virtual void InitializeDriver() = 0; + virtual void FinalizeDriver() = 0; + + virtual Result GetDeviceSystemEvent(IDevice *device) = 0; + virtual Result SetDeviceInterruptEnabled(IDevice *device, bool enable) = 0; + + /* TODO: Eventually implement proper error status enum? */ + virtual Result GetDeviceErrorStatus(u32 *out, IDevice *device) = 0; + virtual Result SetDeviceErrorStatus(IDevice *device, u32 status) = 0; + + virtual Result GetBatterySocRep(float *out_percent, IDevice *device) = 0; + + virtual Result GetBatterySocVf(float *out_percent, IDevice *device) = 0; + + virtual Result GetBatteryFullCapacity(u32 *out_mah, IDevice *device) = 0; + virtual Result GetBatteryRemainingCapacity(u32 *out_mah, IDevice *device) = 0; + + virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) = 0; + virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) = 0; + virtual Result SetBatteryPercentageFullThreshold(IDevice *device, float percentage) = 0; + + virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) = 0; + virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) = 0; + + virtual Result GetChargerFastChargeCurrentLimit(u32 *out_ma, IDevice *device) = 0; + virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, u32 ma) = 0; + + virtual Result GetChargerChargeVoltageLimit(u32 *out_mv, IDevice *device) = 0; + virtual Result SetChargerChargeVoltageLimit(IDevice *device, u32 mv) = 0; + + virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) = 0; + + virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) = 0; + virtual Result SetChargerHiZEnabled(IDevice *device, bool en) = 0; + + virtual Result GetBatteryAverageCurrent(u32 *out_ma, IDevice *device) = 0; + virtual Result GetBatteryCurrent(u32 *out_ma, IDevice *device) = 0; + + virtual Result GetChargerInputCurrentLimit(u32 *out_ma, IDevice *device) = 0; + virtual Result SetChargerInputCurrentLimit(IDevice *device, u32 ma) = 0; + + virtual Result GetChargerInputVoltageLimit(u32 *out_mv, IDevice *device) = 0; + virtual Result SetChargerInputVoltageLimit(IDevice *device, u32 mv) = 0; + + virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) = 0; + virtual Result SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) = 0; + + virtual Result GetBatteryNeedToRestoreParameters(bool *out, IDevice *device) = 0; + virtual Result SetBatteryNeedToRestoreParameters(IDevice *device, bool en) = 0; + + virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) = 0; + virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) = 0; + + virtual Result IsBatteryRemoved(bool *out, IDevice *device) = 0; + + virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) = 0; + + virtual Result GetBatteryCycles(u32 *out, IDevice *device) = 0; + virtual Result SetBatteryCycles(IDevice *device, u32 cycles) = 0; + + virtual Result GetBatteryAge(float *out_percent, IDevice *device) = 0; + + virtual Result GetBatteryTemperature(float *out_c, IDevice *device) = 0; + virtual Result GetBatteryMaximumTemperature(float *out_c, IDevice *device) = 0; + + virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) = 0; + virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) = 0; + + virtual Result GetBatteryVCell(u32 *out_mv, IDevice *device) = 0; + virtual Result GetBatteryAverageVCell(u32 *out_mv, IDevice *device) = 0; + + virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) = 0; + + virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, u32 mv) = 0; + + virtual Result GetBatteryOpenCircuitVoltage(u32 *out_mv, IDevice *device) = 0; + + virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, u32 mv) = 0; + + virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) = 0; + virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) = 0; + + virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) = 0; + virtual Result ResetChargerWatchdogTimer(IDevice *device) = 0; + + virtual Result GetChargerBatteryCompensation(u32 *out_mo, IDevice *device) = 0; + virtual Result SetChargerBatteryCompensation(IDevice *device, u32 mo) = 0; + + virtual Result GetChargerVoltageClamp(u32 *out_mv, IDevice *device) = 0; + virtual Result SetChargerVoltageClamp(IDevice *device, u32 mv) = 0; + }; + +} diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp b/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp new file mode 100644 index 000000000..cacfdd3dd --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp @@ -0,0 +1,138 @@ +/* + * 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" + +namespace ams::powctl::impl { + + namespace { + + os::ThreadType g_interrupt_thread; + + constexpr inline size_t InterruptThreadStackSize = os::MemoryPageSize; + alignas(os::MemoryPageSize) u8 g_interrupt_thread_stack[InterruptThreadStackSize]; + + constinit u8 g_unit_heap_memory[2_KB]; + constinit lmem::HeapHandle g_unit_heap_handle; + constinit sf::UnitHeapMemoryResource g_unit_heap_memory_resource; + + IPowerControlDriver::List &GetDriverList() { + static IPowerControlDriver::List s_driver_list; + return s_driver_list; + } + + ddsf::EventHandlerManager &GetInterruptHandlerManager() { + static ddsf::EventHandlerManager s_interrupt_handler_manager; + return s_interrupt_handler_manager; + } + + ddsf::DeviceCodeEntryManager &GetDeviceCodeEntryManager() { + static ddsf::DeviceCodeEntryManager s_device_code_entry_manager = [] { + /* Initialize the entry code heap. */ + g_unit_heap_handle = lmem::CreateUnitHeap(g_unit_heap_memory, sizeof(g_unit_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe); + + /* Initialize the entry code memory resource. */ + g_unit_heap_memory_resource.Attach(g_unit_heap_handle); + + /* Make the entry manager using the newly initialized memory resource. */ + return ddsf::DeviceCodeEntryManager(std::addressof(g_unit_heap_memory_resource)); + }(); + + return s_device_code_entry_manager; + } + + void InterruptThreadFunction(void *arg) { + AMS_UNUSED(arg); + GetInterruptHandlerManager().LoopAuto(); + } + + } + + void InitializeDrivers() { + /* Ensure the event handler manager is initialized. */ + GetInterruptHandlerManager().Initialize(); + + /* Initialize all registered drivers. */ + for (auto &driver : GetDriverList()) { + driver.SafeCastTo().InitializeDriver(); + } + + /* Create the interrupt thread. */ + R_ABORT_UNLESS(os::CreateThread(std::addressof(g_interrupt_thread), InterruptThreadFunction, nullptr, g_interrupt_thread_stack, InterruptThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(powctl, InterruptHandler))); + os::SetThreadNamePointer(std::addressof(g_interrupt_thread), AMS_GET_SYSTEM_THREAD_NAME(powctl, InterruptHandler)); + os::StartThread(std::addressof(g_interrupt_thread)); + + /* Wait for the interrupt thread to enter the loop. */ + GetInterruptHandlerManager().WaitLoopEnter(); + } + + void FinalizeDrivers() { + /* Request the interrupt thread stop. */ + GetInterruptHandlerManager().RequestStop(); + os::WaitThread(std::addressof(g_interrupt_thread)); + os::DestroyThread(std::addressof(g_interrupt_thread)); + + /* TODO: What else? */ + AMS_ABORT(); + } + + void RegisterDriver(IPowerControlDriver *driver) { + AMS_ASSERT(driver != nullptr); + GetDriverList().push_back(*driver); + } + + void UnregisterDriver(IPowerControlDriver *driver) { + AMS_ASSERT(driver != nullptr); + if (driver->IsLinkedToList()) { + auto &list = GetDriverList(); + list.erase(list.iterator_to(*driver)); + } + } + + Result RegisterDeviceCode(DeviceCode device_code, IDevice *device) { + AMS_ASSERT(device != nullptr); + R_TRY(GetDeviceCodeEntryManager().Add(device_code, device)); + return ResultSuccess(); + } + + bool UnregisterDeviceCode(DeviceCode device_code) { + return GetDeviceCodeEntryManager().Remove(device_code); + } + + void RegisterInterruptHandler(ddsf::IEventHandler *handler) { + AMS_ASSERT(handler != nullptr); + GetInterruptHandlerManager().RegisterHandler(handler); + } + + void UnregisterInterruptHandler(ddsf::IEventHandler *handler) { + AMS_ASSERT(handler != nullptr); + GetInterruptHandlerManager().UnregisterHandler(handler); + } + + Result FindDevice(powctl::impl::IDevice **out, DeviceCode device_code) { + /* Validate output. */ + AMS_ASSERT(out != nullptr); + + /* Find the device. */ + ddsf::IDevice *device; + R_TRY(GetDeviceCodeEntryManager().FindDevice(std::addressof(device), device_code)); + + /* Set output. */ + *out = device->SafeCastToPointer(); + return ResultSuccess(); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_device_management.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_device_management.hpp new file mode 100644 index 000000000..2ab5216d9 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/powctl_device_management.hpp @@ -0,0 +1,36 @@ +/* + * 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" + +namespace ams::powctl::impl { + + void InitializeDrivers(); + void FinalizeDrivers(); + + void RegisterDriver(IPowerControlDriver *driver); + void UnregisterDriver(IPowerControlDriver *driver); + + Result RegisterDeviceCode(DeviceCode device_code, IDevice *device); + bool UnregisterDeviceCode(DeviceCode device_code); + + void RegisterInterruptHandler(ddsf::IEventHandler *handler); + void UnregisterInterruptHandler(ddsf::IEventHandler *handler); + + Result FindDevice(IDevice **out, DeviceCode device_code); + +} 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 new file mode 100644 index 000000000..c9a31a707 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp @@ -0,0 +1,136 @@ +/* + * 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 { + + class IDevice : public ::ams::ddsf::IDevice { + NON_COPYABLE(IDevice); + NON_MOVEABLE(IDevice); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::IDevice, ::ams::ddsf::IDevice); + public: + IDevice() : ddsf::IDevice(false) { /* ... */ } + virtual ~IDevice() { /* ... */ } + }; + + class IPowerControlDriver : public ::ams::ddsf::IDriver { + NON_COPYABLE(IPowerControlDriver); + NON_MOVEABLE(IPowerControlDriver); + AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::IPowerControlDriver, ::ams::ddsf::IDriver); + private: + bool event_handler_enabled; + protected: + constexpr bool IsEventHandlerEnabled() const { + return this->event_handler_enabled; + } + public: + IPowerControlDriver(bool ev) : IDriver(), event_handler_enabled(ev) { /* ... */ } + virtual ~IPowerControlDriver() { /* ... */ } + + virtual void InitializeDriver() = 0; + virtual void FinalizeDriver() = 0; + + virtual Result GetDeviceSystemEvent(IDevice *device) = 0; + virtual Result SetDeviceInterruptEnabled(IDevice *device, bool enable) = 0; + + /* TODO: Eventually implement proper error status enum? */ + virtual Result GetDeviceErrorStatus(u32 *out, IDevice *device) = 0; + virtual Result SetDeviceErrorStatus(IDevice *device, u32 status) = 0; + + virtual Result GetBatterySocRep(float *out_percent, IDevice *device) = 0; + + virtual Result GetBatterySocVf(float *out_percent, IDevice *device) = 0; + + virtual Result GetBatteryFullCapacity(u32 *out_mah, IDevice *device) = 0; + virtual Result GetBatteryRemainingCapacity(u32 *out_mah, IDevice *device) = 0; + + virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) = 0; + virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) = 0; + virtual Result SetBatteryPercentageFullThreshold(IDevice *device, float percentage) = 0; + + virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) = 0; + virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) = 0; + + virtual Result GetChargerFastChargeCurrentLimit(u32 *out_ma, IDevice *device) = 0; + virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, u32 ma) = 0; + + virtual Result GetChargerChargeVoltageLimit(u32 *out_mv, IDevice *device) = 0; + virtual Result SetChargerChargeVoltageLimit(IDevice *device, u32 mv) = 0; + + virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) = 0; + + virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) = 0; + virtual Result SetChargerHiZEnabled(IDevice *device, bool en) = 0; + + virtual Result GetBatteryAverageCurrent(u32 *out_ma, IDevice *device) = 0; + virtual Result GetBatteryCurrent(u32 *out_ma, IDevice *device) = 0; + + virtual Result GetChargerInputCurrentLimit(u32 *out_ma, IDevice *device) = 0; + virtual Result SetChargerInputCurrentLimit(IDevice *device, u32 ma) = 0; + + virtual Result GetChargerInputVoltageLimit(u32 *out_mv, IDevice *device) = 0; + virtual Result SetChargerInputVoltageLimit(IDevice *device, u32 mv) = 0; + + virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) = 0; + virtual Result SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) = 0; + + virtual Result GetBatteryNeedToRestoreParameters(bool *out, IDevice *device) = 0; + virtual Result SetBatteryNeedToRestoreParameters(IDevice *device, bool en) = 0; + + virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) = 0; + virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) = 0; + + virtual Result IsBatteryRemoved(bool *out, IDevice *device) = 0; + + virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) = 0; + + virtual Result GetBatteryCycles(u32 *out, IDevice *device) = 0; + virtual Result SetBatteryCycles(IDevice *device, u32 cycles) = 0; + + virtual Result GetBatteryAge(float *out_percent, IDevice *device) = 0; + + virtual Result GetBatteryTemperature(float *out_c, IDevice *device) = 0; + virtual Result GetBatteryMaximumTemperature(float *out_c, IDevice *device) = 0; + + virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) = 0; + virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) = 0; + + virtual Result GetBatteryVCell(u32 *out_mv, IDevice *device) = 0; + virtual Result GetBatteryAverageVCell(u32 *out_mv, IDevice *device) = 0; + + virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) = 0; + + virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, u32 mv) = 0; + + virtual Result GetBatteryOpenCircuitVoltage(u32 *out_mv, IDevice *device) = 0; + + virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, u32 mv) = 0; + + virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) = 0; + virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) = 0; + + virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) = 0; + virtual Result ResetChargerWatchdogTimer(IDevice *device) = 0; + + virtual Result GetChargerBatteryCompensation(u32 *out_mo, IDevice *device) = 0; + virtual Result SetChargerBatteryCompensation(IDevice *device, u32 mo) = 0; + + virtual Result GetChargerVoltageClamp(u32 *out_mv, IDevice *device) = 0; + virtual Result SetChargerVoltageClamp(IDevice *device, u32 mv) = 0; + }; + +} diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp new file mode 100644 index 000000000..6a9623f4f --- /dev/null +++ b/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp @@ -0,0 +1,32 @@ +/* + * 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" + +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + + #include "board/nintendo_nx/powctl_board_impl.hpp" + + namespace ams::powctl::impl::board { + using namespace ams::powctl::impl::board::nintendo_nx; + } + +#else + + #error "Unknown board for ams::powctl::impl" + +#endif diff --git a/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp b/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp new file mode 100644 index 000000000..ba16bb4aa --- /dev/null +++ b/libraries/libstratosphere/source/powctl/powctl_battery_api.cpp @@ -0,0 +1,439 @@ +/* + * 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 "impl/powctl_i_power_control_driver.hpp" +#include "impl/powctl_device_management.hpp" + +namespace ams::powctl { + + namespace { + + impl::SessionImpl &GetOpenSessionImpl(Session &session) { + AMS_ASSERT(session.has_session); + auto &impl = GetReference(session.impl_storage); + AMS_ASSERT(impl.IsOpen()); + return impl; + } + + } + + Result GetBatterySocRep(float *out_percent, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatterySocRep(out_percent, std::addressof(device)); + } + + Result GetBatterySocVf(float *out_percent, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatterySocVf(out_percent, std::addressof(device)); + } + + Result GetBatteryFullCapacity(u32 *out_mah, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryFullCapacity(out_mah, std::addressof(device)); + } + + Result GetBatteryRemainingCapacity(u32 *out_mah, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryRemainingCapacity(out_mah, std::addressof(device)); + } + + Result SetBatteryPercentageMinimumAlertThreshold(Session &session, float percentage) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryPercentageMinimumAlertThreshold(std::addressof(device), percentage); + } + + Result SetBatteryPercentageMaximumAlertThreshold(Session &session, float percentage) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryPercentageMaximumAlertThreshold(std::addressof(device), percentage); + } + + Result SetBatteryPercentageFullThreshold(Session &session, float percentage) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryPercentageFullThreshold(std::addressof(device), percentage); + } + + Result GetBatteryAverageCurrent(u32 *out_ma, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryAverageCurrent(out_ma, std::addressof(device)); + } + + Result GetBatteryCurrent(u32 *out_ma, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryCurrent(out_ma, std::addressof(device)); + } + + Result GetBatteryInternalState(void *dst, size_t *out_size, Session &session, size_t dst_size) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryInternalState(dst, out_size, std::addressof(device), dst_size); + } + + Result SetBatteryInternalState(Session &session, const void *src, size_t src_size) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryInternalState(std::addressof(device), src, src_size); + } + + Result GetBatteryNeedToRestoreParameters(bool *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryNeedToRestoreParameters(out, std::addressof(device)); + } + + Result SetBatteryNeedToRestoreParameters(Session &session, bool en) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryNeedToRestoreParameters(std::addressof(device), en); + } + + Result IsBatteryI2cShutdownEnabled(bool *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().IsBatteryI2cShutdownEnabled(out, std::addressof(device)); + } + + Result SetBatteryI2cShutdownEnabled(Session &session, bool en) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryI2cShutdownEnabled(std::addressof(device), en); + } + + Result IsBatteryRemoved(bool *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().IsBatteryRemoved(out, std::addressof(device)); + } + + Result GetBatteryCycles(u32 *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryCycles(out, std::addressof(device)); + } + + Result SetBatteryCycles(Session &session, u32 cycles) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryCycles(std::addressof(device), cycles); + } + + Result GetBatteryAge(float *out_percent, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryAge(out_percent, std::addressof(device)); + } + + Result GetBatteryTemperature(float *out_c, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryTemperature(out_c, std::addressof(device)); + } + + Result GetBatteryMaximumTemperature(float *out_c, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryMaximumTemperature(out_c, std::addressof(device)); + } + + Result SetBatteryTemperatureMinimumAlertThreshold(Session &session, float c) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryTemperatureMinimumAlertThreshold(std::addressof(device), c); + } + + Result SetBatteryTemperatureMaximumAlertThreshold(Session &session, float c) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryTemperatureMaximumAlertThreshold(std::addressof(device), c); + } + + Result GetBatteryVCell(u32 *out_mv, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryVCell(out_mv, std::addressof(device)); + } + + Result GetBatteryAverageVCell(u32 *out_mv, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryAverageVCell(out_mv, std::addressof(device)); + } + + Result GetBatteryAverageVCellTime(TimeSpan *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryAverageVCellTime(out, std::addressof(device)); + } + + Result GetBatteryOpenCircuitVoltage(u32 *out_mv, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetBatteryOpenCircuitVoltage(out_mv, std::addressof(device)); + } + + Result SetBatteryVoltageMinimumAlertThreshold(Session &session, u32 mv) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryVoltageMinimumAlertThreshold(std::addressof(device), mv); + } + + Result SetBatteryVoltageMaximumAlertThreshold(Session &session, u32 mv) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetBatteryVoltageMaximumAlertThreshold(std::addressof(device), mv); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp b/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp new file mode 100644 index 000000000..eb9fbff65 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/powctl_charger_api.cpp @@ -0,0 +1,329 @@ +/* + * 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 "impl/powctl_i_power_control_driver.hpp" +#include "impl/powctl_device_management.hpp" + +namespace ams::powctl { + + namespace { + + impl::SessionImpl &GetOpenSessionImpl(Session &session) { + AMS_ASSERT(session.has_session); + auto &impl = GetReference(session.impl_storage); + AMS_ASSERT(impl.IsOpen()); + return impl; + } + + } + + Result GetChargerChargeCurrentState(ChargeCurrentState *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerChargeCurrentState(out, std::addressof(device)); + } + + Result SetChargerChargeCurrentState(Session &session, ChargeCurrentState state) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerChargeCurrentState(std::addressof(device), state); + } + + Result GetChargerFastChargeCurrentLimit(u32 *out_ma, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerFastChargeCurrentLimit(out_ma, std::addressof(device)); + } + + Result SetChargerFastChargeCurrentLimit(Session &session, u32 ma) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerFastChargeCurrentLimit(std::addressof(device), ma); + } + + Result GetChargerChargeVoltageLimit(u32 *out_mv, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerChargeVoltageLimit(out_mv, std::addressof(device)); + } + + Result SetChargerChargeVoltageLimit(Session &session, u32 mv) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerChargeVoltageLimit(std::addressof(device), mv); + } + + Result SetChargerChargerConfiguration(Session &session, ChargerConfiguration cfg) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerChargerConfiguration(std::addressof(device), cfg); + } + + Result IsChargerHiZEnabled(bool *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().IsChargerHiZEnabled(out, std::addressof(device)); + } + + Result SetChargerHiZEnabled(Session &session, bool en) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerHiZEnabled(std::addressof(device), en); + } + + Result GetChargerInputCurrentLimit(u32 *out_ma, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerInputCurrentLimit(out_ma, std::addressof(device)); + } + + Result SetChargerInputCurrentLimit(Session &session, u32 ma) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerInputCurrentLimit(std::addressof(device), ma); + } + + Result GetChargerInputVoltageLimit(u32 *out_mv, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerInputVoltageLimit(out_mv, std::addressof(device)); + } + + Result SetChargerInputVoltageLimit(Session &session, u32 mv) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerInputVoltageLimit(std::addressof(device), mv); + } + + Result GetChargerChargerStatus(ChargerStatus *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerChargerStatus(out, std::addressof(device)); + } + + Result IsChargerWatchdogTimerEnabled(bool *out, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().IsChargerWatchdogTimerEnabled(out, std::addressof(device)); + } + + Result SetChargerWatchdogTimerEnabled(Session &session, bool en) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerWatchdogTimerEnabled(std::addressof(device), en); + } + + Result SetChargerWatchdogTimerTimeout(Session &session, TimeSpan timeout) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerWatchdogTimerTimeout(std::addressof(device), timeout); + } + + Result ResetChargerWatchdogTimer(Session &session); + + Result GetChargerBatteryCompensation(u32 *out_mo, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerBatteryCompensation(out_mo, std::addressof(device)); + } + + Result SetChargerBatteryCompensation(Session &session, u32 mo) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerBatteryCompensation(std::addressof(device), mo); + } + + Result GetChargerVoltageClamp(u32 *out_mv, Session &session) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Read)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().GetChargerVoltageClamp(out_mv, std::addressof(device)); + } + + Result SetChargerVoltageClamp(Session &session, u32 mv) { + /* Get the session impl. */ + auto &impl = GetOpenSessionImpl(session); + + /* Check the access mode. */ + R_TRY(impl.CheckAccess(ddsf::AccessMode_Write)); + + /* Get the device. */ + auto &device = impl.GetDevice().SafeCastTo(); + + /* Call into the driver. */ + return device.GetDriver().SafeCastTo().SetChargerVoltageClamp(std::addressof(device), mv); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/powctl/powctl_driver_api.cpp b/libraries/libstratosphere/source/powctl/powctl_driver_api.cpp new file mode 100644 index 000000000..ad5e2ed20 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/powctl_driver_api.cpp @@ -0,0 +1,39 @@ +/* + * 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 "impl/powctl_select_board_driver.hpp" +#include "impl/powctl_device_management.hpp" + +namespace ams::powctl { + + void Initialize(bool enable_interrupt_handlers) { + /* Initialize the board driver. */ + impl::board::Initialize(enable_interrupt_handlers); + + /* Initialize drivers. */ + impl::InitializeDrivers(); + + } + + void Finalize() { + /* Finalize drivers. */ + impl::FinalizeDrivers(); + + /* Finalize the board driver. */ + impl::board::Finalize(); + } + +} diff --git a/libraries/libstratosphere/source/powctl/powctl_session_api.cpp b/libraries/libstratosphere/source/powctl/powctl_session_api.cpp new file mode 100644 index 000000000..3b46ab0b6 --- /dev/null +++ b/libraries/libstratosphere/source/powctl/powctl_session_api.cpp @@ -0,0 +1,89 @@ +/* + * 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 "impl/powctl_device_management.hpp" + +namespace ams::powctl { + + namespace { + + ddsf::AccessMode SanitizeAccessMode(ddsf::AccessMode access_mode) { + switch (access_mode) { + case ddsf::AccessMode_Read: + case ddsf::AccessMode_Write: + case ddsf::AccessMode_ReadWrite: + case ddsf::AccessMode_WriteShared: + case ddsf::AccessMode_ReadWriteShared: + return access_mode; + default: + return ddsf::AccessMode_None; + } + } + + impl::SessionImpl &GetSessionImpl(Session &session) { + return GetReference(session.impl_storage); + } + + void DestroySession(Session &session) { + GetSessionImpl(session).~SessionImpl(); + session.has_session = false; + } + + void DestroySessionIfNecessary(Session &session) { + if (session.has_session) { + DestroySession(session); + } + } + + void CloseSessionIfOpen(Session &session) { + if (session.has_session && GetSessionImpl(session).IsOpen()) { + DestroySession(session); + } + } + + } + + Result OpenSession(Session *out, DeviceCode device_code, ddsf::AccessMode access_mode) { + /* Validate input. */ + AMS_ASSERT(out != nullptr); + access_mode = SanitizeAccessMode(access_mode); + + /* Find the target device. */ + impl::IDevice *device = nullptr; + R_TRY(impl::FindDevice(std::addressof(device), device_code)); + + /* Clean up the session if we have one. */ + DestroySessionIfNecessary(*out); + + /* Construct the session. */ + new (std::addressof(GetSessionImpl(*out))) impl::SessionImpl; + auto guard = SCOPE_GUARD { DestroySessionIfNecessary(*out); }; + + /* Try to open the session. */ + R_TRY(ddsf::OpenSession(device, std::addressof(GetSessionImpl(*out)), access_mode)); + + /* We opened the session! */ + guard.Cancel(); + return ResultSuccess(); + } + + void CloseSession(Session &session) { + /* This seems extremely unnecessary/duplicate, but it's what Nintendo does. */ + CloseSessionIfOpen(session); + DestroySession(session); + } + +} \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/results.hpp b/libraries/libvapours/include/vapours/results.hpp index 21d141c3e..b69533be7 100644 --- a/libraries/libvapours/include/vapours/results.hpp +++ b/libraries/libvapours/include/vapours/results.hpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/results/powctl_results.hpp b/libraries/libvapours/include/vapours/results/powctl_results.hpp new file mode 100644 index 000000000..b071ee1ff --- /dev/null +++ b/libraries/libvapours/include/vapours/results/powctl_results.hpp @@ -0,0 +1,28 @@ +/* + * 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 { + + R_DEFINE_NAMESPACE_RESULT_MODULE(198); + + R_DEFINE_ERROR_RESULT(NotSupported, 1); + R_DEFINE_ERROR_RESULT(InvalidArgument, 2); + R_DEFINE_ERROR_RESULT(NotAvailable, 3); + +} diff --git a/stratosphere/boot/source/boot_driver_management.cpp b/stratosphere/boot/source/boot_driver_management.cpp index 0bfcb18a6..b556529e6 100644 --- a/stratosphere/boot/source/boot_driver_management.cpp +++ b/stratosphere/boot/source/boot_driver_management.cpp @@ -49,4 +49,9 @@ namespace ams::boot { pwm::driver::Initialize(); } + void FinalizeI2cDriverLibrary() { + /* TODO */ + AMS_ABORT(); + } + } diff --git a/stratosphere/boot/source/boot_driver_management.hpp b/stratosphere/boot/source/boot_driver_management.hpp index 401516d1d..aab6e5523 100644 --- a/stratosphere/boot/source/boot_driver_management.hpp +++ b/stratosphere/boot/source/boot_driver_management.hpp @@ -19,6 +19,7 @@ namespace ams::boot { void InitializeGpioDriverLibrary(); void InitializeI2cDriverLibrary(); + void FinalizeI2cDriverLibrary(); } diff --git a/stratosphere/boot/source/boot_fan_enable.cpp b/stratosphere/boot/source/boot_fan_enable.cpp index 2a6b58ef9..282ab1224 100644 --- a/stratosphere/boot/source/boot_fan_enable.cpp +++ b/stratosphere/boot/source/boot_fan_enable.cpp @@ -18,7 +18,7 @@ namespace ams::boot { - void SetFanEnabled() { + void SetFanPowerEnabled() { if (spl::GetHardwareType() == spl::HardwareType::Copper) { /* TODO */ /* boot::gpio::Configure(GpioPadName_FanEnable); */ diff --git a/stratosphere/boot/source/boot_fan_enable.hpp b/stratosphere/boot/source/boot_fan_enable.hpp index 6e70ab1db..5fd24b555 100644 --- a/stratosphere/boot/source/boot_fan_enable.hpp +++ b/stratosphere/boot/source/boot_fan_enable.hpp @@ -18,6 +18,6 @@ namespace ams::boot { - void SetFanEnabled(); + void SetFanPowerEnabled(); } diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 49d4917bc..6be74c637 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -191,14 +191,25 @@ int main(int argc, char **argv) /* Initialize the gpio server library. */ boot::InitializeGpioDriverLibrary(); + /* Initialize the i2c server library. */ + boot::InitializeI2cDriverLibrary(); + + /* Get the hardware type. */ + const auto hw_type = spl::GetHardwareType(); + + /* Initialize the power control library without interrupt event handling. */ + if (hw_type != spl::HardwareType::Calcio) { + powctl::Initialize(false); + } + /* Check USB PLL/UTMIP clock. */ boot::CheckClock(); /* Talk to PMIC/RTC, set boot reason with SPL. */ boot::DetectBootReason(); - const auto hw_type = spl::GetHardwareType(); - if (hw_type != spl::HardwareType::Copper && hw_type != spl::HardwareType::Calcio) { + /* Display the splash screen and check the battery charge. */ + if (hw_type != spl::HardwareType::Calcio) { /* Display splash screen for two seconds. */ boot::ShowSplashScreen(); @@ -213,16 +224,24 @@ int main(int argc, char **argv) gpio::driver::SetInitialWakePinConfig(); /* Configure output clock. */ - if (hw_type != spl::HardwareType::Copper && hw_type != spl::HardwareType::Calcio) { + if (hw_type != spl::HardwareType::Calcio) { boot::SetInitialClockConfiguration(); } /* Set Fan enable config (Copper only). */ - boot::SetFanEnabled(); + boot::SetFanPowerEnabled(); /* Repair boot partitions in NAND if needed. */ boot::CheckAndRepairBootImages(); + /* Finalize the power control library. */ + if (hw_type != spl::HardwareType::Calcio) { + powctl::Finalize(); + } + + /* Finalize the i2c server library. */ + boot::FinalizeI2cDriverLibrary(); + /* Tell PM to start boot2. */ R_ABORT_UNLESS(pmshellNotifyBootFinished());