mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
boot: refactor battery checking to use new powctl apis
This commit is contained in:
parent
485304bd17
commit
708f5bf1fb
44 changed files with 1426 additions and 1554 deletions
|
@ -41,6 +41,7 @@
|
||||||
/* At this point, just include the rest alphabetically. */
|
/* At this point, just include the rest alphabetically. */
|
||||||
/* TODO: Figure out optimal order. */
|
/* TODO: Figure out optimal order. */
|
||||||
#include <stratosphere/boot2.hpp>
|
#include <stratosphere/boot2.hpp>
|
||||||
|
#include <stratosphere/cal.hpp>
|
||||||
#include <stratosphere/capsrv.hpp>
|
#include <stratosphere/capsrv.hpp>
|
||||||
#include <stratosphere/cfg.hpp>
|
#include <stratosphere/cfg.hpp>
|
||||||
#include <stratosphere/clkrst.hpp>
|
#include <stratosphere/clkrst.hpp>
|
||||||
|
|
19
libraries/libstratosphere/include/stratosphere/cal.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/cal.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stratosphere/cal/cal_battery_api.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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::cal {
|
||||||
|
|
||||||
|
Result GetBatteryVersion(u8 *out);
|
||||||
|
Result GetBatteryVendor(size_t *out_vendor_size, void *dst, size_t dst_size);
|
||||||
|
|
||||||
|
}
|
|
@ -20,4 +20,7 @@
|
||||||
#include <stratosphere/powctl/powctl_session_api.hpp>
|
#include <stratosphere/powctl/powctl_session_api.hpp>
|
||||||
#include <stratosphere/powctl/powctl_battery_api.hpp>
|
#include <stratosphere/powctl/powctl_battery_api.hpp>
|
||||||
#include <stratosphere/powctl/powctl_charger_api.hpp>
|
#include <stratosphere/powctl/powctl_charger_api.hpp>
|
||||||
|
#include <stratosphere/powctl/impl/powctl_battery_charge_percentage.hpp>
|
||||||
#include <stratosphere/powctl/driver/powctl_driver_api.hpp>
|
#include <stratosphere/powctl/driver/powctl_driver_api.hpp>
|
||||||
|
#include <stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp>
|
||||||
|
#include <stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp>
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/powctl/powctl_types.hpp>
|
||||||
|
#include <stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp>
|
||||||
|
|
||||||
|
namespace ams::powctl::driver::impl {
|
||||||
|
|
||||||
|
class ChargeArbiter {
|
||||||
|
private:
|
||||||
|
const ChargeParametersRule *rules;
|
||||||
|
size_t num_rules;
|
||||||
|
int charge_voltage_limit;
|
||||||
|
BatteryTemperatureLevel temperature_level;
|
||||||
|
int avg_v_cell;
|
||||||
|
int open_circuit_voltage;
|
||||||
|
bool has_battery_done_current;
|
||||||
|
int battery_done_current;
|
||||||
|
PowerState power_state;
|
||||||
|
const ChargeParametersRule *selected_rule;
|
||||||
|
bool check_battery_done_current;
|
||||||
|
private:
|
||||||
|
static constexpr bool IsInRange(int value, int min, int max) {
|
||||||
|
if (!(min <= value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max == std::numeric_limits<int>::max()) {
|
||||||
|
return value <= max;
|
||||||
|
} else {
|
||||||
|
return value < max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAcceptablePowerState(const PowerState *acceptable, size_t num_acceptable) const {
|
||||||
|
for (size_t i = 0; i < num_acceptable; ++i) {
|
||||||
|
if (this->power_state == acceptable[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
ChargeArbiter(const ChargeParametersRule *r, size_t nr, int cvl)
|
||||||
|
: rules(r), num_rules(nr), charge_voltage_limit(cvl), temperature_level(BatteryTemperatureLevel::Medium),
|
||||||
|
avg_v_cell(4080), open_circuit_voltage(4001), has_battery_done_current(false), battery_done_current(0),
|
||||||
|
power_state(PowerState::FullAwake), selected_rule(nullptr), check_battery_done_current(false)
|
||||||
|
{
|
||||||
|
this->UpdateSelectedRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBatteryTemperatureLevel(BatteryTemperatureLevel btl) {
|
||||||
|
this->temperature_level = btl;
|
||||||
|
this->UpdateSelectedRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBatteryAverageVCell(int avg) {
|
||||||
|
this->avg_v_cell = avg;
|
||||||
|
this->UpdateSelectedRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBatteryOpenCircuitVoltage(int ocv) {
|
||||||
|
this->open_circuit_voltage = ocv;
|
||||||
|
this->UpdateSelectedRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBatteryDoneCurrent(int current) {
|
||||||
|
this->battery_done_current = current;
|
||||||
|
this->has_battery_done_current = true;
|
||||||
|
this->UpdateSelectedRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPowerState(PowerState ps) {
|
||||||
|
this->power_state = ps;
|
||||||
|
this->UpdateSelectedRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetChargeVoltageLimit() const {
|
||||||
|
return this->charge_voltage_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBatteryDoneCurrentAcceptable(int current) const {
|
||||||
|
const auto *rule = this->GetSelectedRule();
|
||||||
|
AMS_ASSERT(rule != nullptr);
|
||||||
|
|
||||||
|
return IsInRange(0, rule->min_battery_done_current, rule->max_battery_done_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChargeParametersRule *GetSelectedRule() const {
|
||||||
|
return this->selected_rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateSelectedRule() {
|
||||||
|
/* Try to find an entry that fits our current requirements. */
|
||||||
|
const ChargeParametersRule *best_rule = nullptr;
|
||||||
|
for (size_t i = 0; i < this->num_rules; ++i) {
|
||||||
|
/* Get the current rule. */
|
||||||
|
const ChargeParametersRule &cur_rule = this->rules[i];
|
||||||
|
|
||||||
|
/* Check the temperature level. */
|
||||||
|
if (this->temperature_level != cur_rule.temperature_level) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that average voltage is in range. */
|
||||||
|
if (!IsInRange(this->avg_v_cell, cur_rule.min_avg_v_cell, cur_rule.max_avg_v_cell)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that open circuit voltage is in range. */
|
||||||
|
if (!IsInRange(this->open_circuit_voltage, cur_rule.min_open_circuit_voltage, cur_rule.max_open_circuit_voltage)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if our power state is acceptable. */
|
||||||
|
if (!this->IsAcceptablePowerState(cur_rule.acceptable_power_states, cur_rule.num_acceptable_power_states)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The limit is probably acceptable. */
|
||||||
|
if (this->selected_rule != std::addressof(cur_rule)) {
|
||||||
|
/* We're selecting a new rule. Check if our need to deal with battery current is acceptable. */
|
||||||
|
if (cur_rule.check_battery_current && this->check_battery_done_current) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set whether we need to check the battery done current. */
|
||||||
|
this->has_battery_done_current = false;
|
||||||
|
this->check_battery_done_current |= cur_rule.check_battery_current;
|
||||||
|
} else {
|
||||||
|
/* We're selecting the currently selected rule. Make sure the battery done current is acceptable if we have one. */
|
||||||
|
if (this->has_battery_done_current && !IsInRange(this->battery_done_current, cur_rule.min_battery_done_current, cur_rule.max_battery_done_current)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select the current rule. */
|
||||||
|
best_rule = std::addressof(cur_rule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update our selected rule. */
|
||||||
|
this->selected_rule = best_rule;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/powctl/powctl_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::powctl::driver::impl {
|
||||||
|
|
||||||
|
struct ChargeParametersRule {
|
||||||
|
BatteryTemperatureLevel temperature_level;
|
||||||
|
int min_avg_v_cell;
|
||||||
|
int max_avg_v_cell;
|
||||||
|
int min_open_circuit_voltage;
|
||||||
|
int max_open_circuit_voltage;
|
||||||
|
int min_battery_done_current;
|
||||||
|
int max_battery_done_current;
|
||||||
|
const PowerState *acceptable_power_states;
|
||||||
|
size_t num_acceptable_power_states;
|
||||||
|
bool check_battery_current;
|
||||||
|
bool reinitialize_charger;
|
||||||
|
int charge_voltage_limit;
|
||||||
|
int fast_charge_current_limit;
|
||||||
|
int battery_compensation;
|
||||||
|
int voltage_clamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnknownParameterX {
|
||||||
|
int _00;
|
||||||
|
int _04;
|
||||||
|
double _08;
|
||||||
|
double _10;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChargeParameters {
|
||||||
|
int temp_min;
|
||||||
|
int temp_low;
|
||||||
|
int temp_high;
|
||||||
|
int temp_max;
|
||||||
|
int low_voltage_fast_charge_current_limit;
|
||||||
|
int default_charge_voltage_limit;
|
||||||
|
const UnknownParameterX *unknown_x_table;
|
||||||
|
size_t x_table_size;
|
||||||
|
double _28;
|
||||||
|
double _30;
|
||||||
|
const ChargeParametersRule *rules;
|
||||||
|
size_t num_rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChargeParameters &GetChargeParameters();
|
||||||
|
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/powctl/powctl_types.hpp>
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||||
|
|
||||||
|
#include <stratosphere/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.hpp>
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "unknown board for powctl::driver::impl::ChargerParameters"
|
||||||
|
#endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/powctl/powctl_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::powctl::impl {
|
||||||
|
|
||||||
|
constexpr inline const double MinRawDefaultPercentage = 3.0;
|
||||||
|
constexpr inline const double MaxRawDefaultPercentage = 99.0;
|
||||||
|
|
||||||
|
constexpr inline const double MinRawThresholdPercentage = 11.0;
|
||||||
|
|
||||||
|
constexpr inline const int MinDisplayPercentage = 1;
|
||||||
|
constexpr inline const int MaxDisplayPercentage = 100;
|
||||||
|
|
||||||
|
constexpr inline void CalculateMarginatedRawPercentage(double *out_marginated_min, double *out_marginated_max, double min, double max) {
|
||||||
|
/* Ensure minimum is in correct range. */
|
||||||
|
min = std::max(std::min(min, MinRawThresholdPercentage), MinRawDefaultPercentage);
|
||||||
|
|
||||||
|
/* Calculate the marginated values. */
|
||||||
|
constexpr const double MinMarginPercentage = 0.93359375;
|
||||||
|
constexpr const double MaxMarginPercentage = -0.83593750;
|
||||||
|
|
||||||
|
const auto margin_factor = (max - min) / (MaxRawDefaultPercentage - MinRawDefaultPercentage);
|
||||||
|
*out_marginated_min = min + MinMarginPercentage * margin_factor;
|
||||||
|
*out_marginated_max = max + MaxMarginPercentage * margin_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline int GetDisplayPercentage(double raw_percentage, double min, double max) {
|
||||||
|
/* Calculate the display percentage. */
|
||||||
|
constexpr const double BaseDisplayPercentage = 2.0;
|
||||||
|
const auto display_percentage = BaseDisplayPercentage + ((static_cast<double>(MaxDisplayPercentage - MinDisplayPercentage) * (raw_percentage - min)) / (max - min));
|
||||||
|
|
||||||
|
/* Clamp the display percentage within bounds. */
|
||||||
|
return std::max(std::min(static_cast<int>(display_percentage), MaxDisplayPercentage), MinDisplayPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline int ConvertBatteryChargePercentage(double raw_percentage, double min, double max) {
|
||||||
|
/* Marginate the min/max. */
|
||||||
|
double marginated_min = 0.0, marginated_max = 0.0;
|
||||||
|
CalculateMarginatedRawPercentage(std::addressof(marginated_min), std::addressof(marginated_max), min, max);
|
||||||
|
|
||||||
|
/* Convert to display percentage. */
|
||||||
|
return GetDisplayPercentage(raw_percentage, marginated_min, marginated_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline int ConvertBatteryChargePercentage(double raw_percentage) {
|
||||||
|
return ConvertBatteryChargePercentage(raw_percentage, MinRawDefaultPercentage, MaxRawDefaultPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,15 +25,15 @@ namespace ams::powctl {
|
||||||
|
|
||||||
Result GetBatterySocVf(float *out_percent, Session &session);
|
Result GetBatterySocVf(float *out_percent, Session &session);
|
||||||
|
|
||||||
Result GetBatteryFullCapacity(u32 *out_mah, Session &session);
|
Result GetBatteryFullCapacity(int *out_mah, Session &session);
|
||||||
Result GetBatteryRemainingCapacity(u32 *out_mah, Session &session);
|
Result GetBatteryRemainingCapacity(int *out_mah, Session &session);
|
||||||
|
|
||||||
Result SetBatteryPercentageMinimumAlertThreshold(Session &session, float percentage);
|
Result SetBatteryPercentageMinimumAlertThreshold(Session &session, float percentage);
|
||||||
Result SetBatteryPercentageMaximumAlertThreshold(Session &session, float percentage);
|
Result SetBatteryPercentageMaximumAlertThreshold(Session &session, float percentage);
|
||||||
Result SetBatteryPercentageFullThreshold(Session &session, float percentage);
|
Result SetBatteryPercentageFullThreshold(Session &session, float percentage);
|
||||||
|
|
||||||
Result GetBatteryAverageCurrent(u32 *out_ma, Session &session);
|
Result GetBatteryAverageCurrent(int *out_ma, Session &session);
|
||||||
Result GetBatteryCurrent(u32 *out_ma, Session &session);
|
Result GetBatteryCurrent(int *out_ma, Session &session);
|
||||||
|
|
||||||
Result GetBatteryInternalState(void *dst, size_t *out_size, Session &session, size_t dst_size);
|
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 SetBatteryInternalState(Session &session, const void *src, size_t src_size);
|
||||||
|
@ -44,10 +44,10 @@ namespace ams::powctl {
|
||||||
Result IsBatteryI2cShutdownEnabled(bool *out, Session &session);
|
Result IsBatteryI2cShutdownEnabled(bool *out, Session &session);
|
||||||
Result SetBatteryI2cShutdownEnabled(Session &session, bool en);
|
Result SetBatteryI2cShutdownEnabled(Session &session, bool en);
|
||||||
|
|
||||||
Result IsBatteryRemoved(bool *out, Session &session);
|
Result IsBatteryPresent(bool *out, Session &session);
|
||||||
|
|
||||||
Result GetBatteryCycles(u32 *out, Session &session);
|
Result GetBatteryCycles(int *out, Session &session);
|
||||||
Result SetBatteryCycles(Session &session, u32 cycles);
|
Result SetBatteryCycles(Session &session, int cycles);
|
||||||
|
|
||||||
Result GetBatteryAge(float *out_percent, Session &session);
|
Result GetBatteryAge(float *out_percent, Session &session);
|
||||||
|
|
||||||
|
@ -57,14 +57,14 @@ namespace ams::powctl {
|
||||||
Result SetBatteryTemperatureMinimumAlertThreshold(Session &session, float c);
|
Result SetBatteryTemperatureMinimumAlertThreshold(Session &session, float c);
|
||||||
Result SetBatteryTemperatureMaximumAlertThreshold(Session &session, float c);
|
Result SetBatteryTemperatureMaximumAlertThreshold(Session &session, float c);
|
||||||
|
|
||||||
Result GetBatteryVCell(u32 *out_mv, Session &session);
|
Result GetBatteryVCell(int *out_mv, Session &session);
|
||||||
Result GetBatteryAverageVCell(u32 *out_mv, Session &session);
|
Result GetBatteryAverageVCell(int *out_mv, Session &session);
|
||||||
|
|
||||||
Result GetBatteryAverageVCellTime(TimeSpan *out, Session &session);
|
Result GetBatteryAverageVCellTime(TimeSpan *out, Session &session);
|
||||||
|
|
||||||
Result GetBatteryOpenCircuitVoltage(u32 *out_mv, Session &session);
|
Result GetBatteryOpenCircuitVoltage(int *out_mv, Session &session);
|
||||||
|
|
||||||
Result SetBatteryVoltageMinimumAlertThreshold(Session &session, u32 mv);
|
Result SetBatteryVoltageMinimumAlertThreshold(Session &session, int mv);
|
||||||
Result SetBatteryVoltageMaximumAlertThreshold(Session &session, u32 mv);
|
Result SetBatteryVoltageMaximumAlertThreshold(Session &session, int mv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,22 +24,22 @@ namespace ams::powctl {
|
||||||
Result GetChargerChargeCurrentState(ChargeCurrentState *out, Session &session);
|
Result GetChargerChargeCurrentState(ChargeCurrentState *out, Session &session);
|
||||||
Result SetChargerChargeCurrentState(Session &session, ChargeCurrentState state);
|
Result SetChargerChargeCurrentState(Session &session, ChargeCurrentState state);
|
||||||
|
|
||||||
Result GetChargerFastChargeCurrentLimit(u32 *out_ma, Session &session);
|
Result GetChargerFastChargeCurrentLimit(int *out_ma, Session &session);
|
||||||
Result SetChargerFastChargeCurrentLimit(Session &session, u32 ma);
|
Result SetChargerFastChargeCurrentLimit(Session &session, int ma);
|
||||||
|
|
||||||
Result GetChargerChargeVoltageLimit(u32 *out_mv, Session &session);
|
Result GetChargerChargeVoltageLimit(int *out_mv, Session &session);
|
||||||
Result SetChargerChargeVoltageLimit(Session &session, u32 mv);
|
Result SetChargerChargeVoltageLimit(Session &session, int mv);
|
||||||
|
|
||||||
Result SetChargerChargerConfiguration(Session &session, ChargerConfiguration cfg);
|
Result SetChargerChargerConfiguration(Session &session, ChargerConfiguration cfg);
|
||||||
|
|
||||||
Result IsChargerHiZEnabled(bool *out, Session &session);
|
Result IsChargerHiZEnabled(bool *out, Session &session);
|
||||||
Result SetChargerHiZEnabled(Session &session, bool en);
|
Result SetChargerHiZEnabled(Session &session, bool en);
|
||||||
|
|
||||||
Result GetChargerInputCurrentLimit(u32 *out_ma, Session &session);
|
Result GetChargerInputCurrentLimit(int *out_ma, Session &session);
|
||||||
Result SetChargerInputCurrentLimit(Session &session, u32 ma);
|
Result SetChargerInputCurrentLimit(Session &session, int ma);
|
||||||
|
|
||||||
Result GetChargerInputVoltageLimit(u32 *out_mv, Session &session);
|
Result GetChargerInputVoltageLimit(int *out_mv, Session &session);
|
||||||
Result SetChargerInputVoltageLimit(Session &session, u32 mv);
|
Result SetChargerInputVoltageLimit(Session &session, int mv);
|
||||||
|
|
||||||
Result GetChargerChargerStatus(ChargerStatus *out, Session &session);
|
Result GetChargerChargerStatus(ChargerStatus *out, Session &session);
|
||||||
|
|
||||||
|
@ -49,10 +49,10 @@ namespace ams::powctl {
|
||||||
Result SetChargerWatchdogTimerTimeout(Session &session, TimeSpan timeout);
|
Result SetChargerWatchdogTimerTimeout(Session &session, TimeSpan timeout);
|
||||||
Result ResetChargerWatchdogTimer(Session &session);
|
Result ResetChargerWatchdogTimer(Session &session);
|
||||||
|
|
||||||
Result GetChargerBatteryCompensation(u32 *out_mo, Session &session);
|
Result GetChargerBatteryCompensation(int *out_mo, Session &session);
|
||||||
Result SetChargerBatteryCompensation(Session &session, u32 mo);
|
Result SetChargerBatteryCompensation(Session &session, int mo);
|
||||||
|
|
||||||
Result GetChargerVoltageClamp(u32 *out_mv, Session &session);
|
Result GetChargerVoltageClamp(int *out_mv, Session &session);
|
||||||
Result SetChargerVoltageClamp(Session &session, u32 mv);
|
Result SetChargerVoltageClamp(Session &session, int mv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ namespace ams::powctl {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ChargerConfiguration {
|
enum ChargerConfiguration {
|
||||||
ChargerConfiguration_ChargeDisable = 0,
|
ChargerConfiguration_ChargeDisable = 1,
|
||||||
ChargerConfiguration_ChargeBattery = 1,
|
ChargerConfiguration_ChargeBattery = 2,
|
||||||
ChargerConfiguration_Otg = 2,
|
ChargerConfiguration_Otg = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ChargeCurrentState {
|
enum ChargeCurrentState {
|
||||||
|
@ -38,4 +38,20 @@ namespace ams::powctl {
|
||||||
ChargeCurrentState_Charging = 0x3,
|
ChargeCurrentState_Charging = 0x3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class BatteryTemperatureLevel {
|
||||||
|
TooLow = 0,
|
||||||
|
Low = 1,
|
||||||
|
Medium = 2,
|
||||||
|
High = 3,
|
||||||
|
TooHigh = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PowerState {
|
||||||
|
FullAwake = 0,
|
||||||
|
MinimumAwake = 1,
|
||||||
|
SleepCharge = 2,
|
||||||
|
SleepDischarge = 3,
|
||||||
|
ShutdownChargeMain = 4,
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -150,6 +150,15 @@ namespace ams::spl {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
|
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
|
||||||
|
|
||||||
|
enum BootReason {
|
||||||
|
BootReason_Unknown = 0,
|
||||||
|
BootReason_AcOk = 1,
|
||||||
|
BootReason_OnKey = 2,
|
||||||
|
BootReason_RtcAlarm1 = 3,
|
||||||
|
BootReason_RtcAlarm2 = 4,
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct AesKey {
|
struct AesKey {
|
||||||
|
|
53
libraries/libstratosphere/source/cal/cal_battery_api.cpp
Normal file
53
libraries/libstratosphere/source/cal/cal_battery_api.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "cal_fs_utils.hpp"
|
||||||
|
|
||||||
|
namespace ams::cal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline s64 BatteryLotOffset = 0x2CE0;
|
||||||
|
constexpr inline size_t BatteryLotSize = 0x20;
|
||||||
|
|
||||||
|
constexpr inline s64 BatteryVersionOffset = 0x4310;
|
||||||
|
constexpr inline size_t BatteryVersionSize = 0x10;
|
||||||
|
|
||||||
|
constexpr inline size_t BatteryVendorSizeMax = 0x18;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetBatteryVersion(u8 *out) {
|
||||||
|
/* Read the battery version. */
|
||||||
|
u8 battery_version[BatteryVersionSize];
|
||||||
|
R_TRY(cal::impl::ReadCalibrationBlock(BatteryVersionOffset, battery_version, sizeof(battery_version)));
|
||||||
|
|
||||||
|
/* Write the output. */
|
||||||
|
*out = battery_version[0];
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetBatteryVendor(size_t *out_vendor_size, void *dst, size_t dst_size) {
|
||||||
|
/* Read the battery lot. */
|
||||||
|
char battery_lot[BatteryLotSize];
|
||||||
|
R_TRY(cal::impl::ReadCalibrationBlock(BatteryLotOffset, battery_lot, sizeof(battery_lot)));
|
||||||
|
|
||||||
|
/* Copy output. */
|
||||||
|
*out_vendor_size = static_cast<size_t>(util::Strlcpy(static_cast<char *>(dst), battery_lot, std::min(dst_size, BatteryVendorSizeMax)));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
libraries/libstratosphere/source/cal/cal_crc_utils.cpp
Normal file
53
libraries/libstratosphere/source/cal/cal_crc_utils.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "cal_crc_utils.hpp"
|
||||||
|
|
||||||
|
namespace ams::cal::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const u16 CrcTable[0x10] = {
|
||||||
|
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
|
||||||
|
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 CalculateCrc16(const void *data, size_t size) {
|
||||||
|
AMS_ASSERT(data != nullptr);
|
||||||
|
|
||||||
|
u16 crc = 0x55AA;
|
||||||
|
const u8 *data_u8 = static_cast<const u8 *>(data);
|
||||||
|
for (size_t i = 0; i < size; ++i) {
|
||||||
|
crc = (crc >> 4) ^ (CrcTable[crc & 0xF]) ^ (CrcTable[(data_u8[i] >> 0) & 0xF]);
|
||||||
|
crc = (crc >> 4) ^ (CrcTable[crc & 0xF]) ^ (CrcTable[(data_u8[i] >> 4) & 0xF]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ValidateCalibrationCrc(const void *data, size_t size) {
|
||||||
|
AMS_ASSERT(data != nullptr);
|
||||||
|
AMS_ASSERT(size >= sizeof(u16));
|
||||||
|
|
||||||
|
const u16 crc = *reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(data) + size - sizeof(u16));
|
||||||
|
R_UNLESS(CalculateCrc16(data, size - sizeof(u16)) == crc, cal::ResultCalibrationDataCrcError());
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,12 +16,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::cal::impl {
|
||||||
|
|
||||||
constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400;
|
u16 CalculateCrc16(const void *data, size_t size);
|
||||||
|
Result ValidateCalibrationCrc(const void *data, size_t size);
|
||||||
/* PMC Access Utilities. */
|
|
||||||
u32 ReadPmcRegister(dd::PhysicalAddress phys_addr);
|
|
||||||
void WritePmcRegister(dd::PhysicalAddress phys_addr, u32 value, u32 mask = std::numeric_limits<u32>::max());
|
|
||||||
|
|
||||||
}
|
}
|
36
libraries/libstratosphere/source/cal/cal_fs_utils.cpp
Normal file
36
libraries/libstratosphere/source/cal/cal_fs_utils.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "cal_crc_utils.hpp"
|
||||||
|
#include "cal_fs_utils.hpp"
|
||||||
|
|
||||||
|
namespace ams::cal::impl {
|
||||||
|
|
||||||
|
Result ReadCalibrationBlock(s64 offset, void *dst, size_t block_size) {
|
||||||
|
/* Open the calibration binary partition. */
|
||||||
|
std::unique_ptr<fs::IStorage> storage;
|
||||||
|
R_TRY(fs::OpenBisPartition(std::addressof(storage), fs::BisPartitionId::CalibrationBinary));
|
||||||
|
|
||||||
|
/* Read data from the partition. */
|
||||||
|
R_TRY(storage->Read(offset, dst, block_size));
|
||||||
|
|
||||||
|
/* Validate the crc. */
|
||||||
|
R_TRY(ValidateCalibrationCrc(dst, block_size));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,10 +16,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::cal::impl {
|
||||||
|
|
||||||
/* Calibration utilities. */
|
Result ReadCalibrationBlock(s64 offset, void *dst, size_t block_size);
|
||||||
u32 GetBatteryVersion();
|
|
||||||
u32 GetBatteryVendor();
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::powctl::driver::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const PowerState AcceptablePowerStates[] = {
|
||||||
|
PowerState::FullAwake,
|
||||||
|
PowerState::MinimumAwake,
|
||||||
|
PowerState::SleepCharge,
|
||||||
|
PowerState::SleepDischarge,
|
||||||
|
PowerState::ShutdownChargeMain,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const PowerState AcceptablePowerStatesForNotAwakeCharge[] = {
|
||||||
|
PowerState::SleepCharge,
|
||||||
|
PowerState::ShutdownChargeMain,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const int Min = std::numeric_limits<int>::min();
|
||||||
|
constexpr inline const int Max = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
constexpr inline const UnknownParameterX UnknownXTableForBatteryVersion2[] = {
|
||||||
|
{ 20000, 4320, 95.0, 100.4 },
|
||||||
|
{ 30000, 4304, 94.0, 99.7 },
|
||||||
|
{ 40000, 4288, 93.0, 98.4 },
|
||||||
|
{ 50000, 4272, 92.0, 97.0 },
|
||||||
|
{ 60000, 4256, 90.0, 95.7 },
|
||||||
|
{ 80000, 4240, 89.0, 94.2 },
|
||||||
|
{ 100000, 4224, 88.0, 93.0 },
|
||||||
|
{ Max, 4192, 85.0, 90.0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Include automatically extracted charger parameters. */
|
||||||
|
#include "powctl_charger_parameters.board.nintendo_nx.inc"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChargeParameters &GetChargeParameters() {
|
||||||
|
/* Get the battery version. */
|
||||||
|
u8 battery_version;
|
||||||
|
if (R_FAILED(cal::GetBatteryVersion(std::addressof(battery_version)))) {
|
||||||
|
battery_version = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (battery_version == 2) {
|
||||||
|
return ChargeParametersForBatteryVersion2;
|
||||||
|
} else if (battery_version == 1) {
|
||||||
|
return ChargeParametersForBatteryVersion1;
|
||||||
|
} else {
|
||||||
|
if (spl::GetHardwareType() == spl::HardwareType::_Five_) {
|
||||||
|
return ChargeParametersForBatteryVersion0ForFive;
|
||||||
|
} else {
|
||||||
|
return ChargeParametersForBatteryVersion0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NOTE: This file is auto-generated by charger_parameters.py, do not edit manually. */
|
||||||
|
|
||||||
|
constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion0[] = {
|
||||||
|
{ BatteryTemperatureLevel::TooLow, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 512, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooLow, 3320, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 768, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Low, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 512, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Low, 3320, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 768, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Medium, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 512, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Medium, 3320, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3952, 512, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, 3320, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3952, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, Min, 3320, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3952, 512, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, 3320, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3952, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion1[] = {
|
||||||
|
{ BatteryTemperatureLevel::TooLow, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 576, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Low, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 576, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Medium, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 1536, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, Min, 3984, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3984, 1536, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, 3984, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 1536, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, Min, 3984, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3984, 1536, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, 3984, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 1536, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion2[] = {
|
||||||
|
{ BatteryTemperatureLevel::TooLow, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4320, 640, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Low, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4320, 640, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Medium, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4320, 1664, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, Min, 4080, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4080, 1664, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, 4080, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4320, 1664, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, Min, 4080, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4080, 1664, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, 4080, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4320, 1664, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParametersRule ChargeParametersRulesForBatteryVersion0ForFive[] = {
|
||||||
|
{ BatteryTemperatureLevel::TooLow, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 768, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Low, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 768, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::Medium, Min, Max, Min, 4001, 2049, Max, AcceptablePowerStatesForNotAwakeCharge, util::size(AcceptablePowerStatesForNotAwakeCharge), true, true, 4000, 3072, 40, 112 },
|
||||||
|
{ BatteryTemperatureLevel::Medium, Min, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 4208, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, Min, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, true, 3952, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::High, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, Min, 4050, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 3952, 2048, 0, 0 },
|
||||||
|
{ BatteryTemperatureLevel::TooHigh, 4050, Max, Min, Max, Min, Max, AcceptablePowerStates, util::size(AcceptablePowerStates), false, false, 4208, 2048, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParameters ChargeParametersForBatteryVersion0 = {
|
||||||
|
4, 17, 51, 60, 512, 4208, nullptr, 0, 95.0, 99.0, ChargeParametersRulesForBatteryVersion0, util::size(ChargeParametersRulesForBatteryVersion0)
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParameters ChargeParametersForBatteryVersion1 = {
|
||||||
|
1, 19, 48, 59, 1536, 4208, nullptr, 0, 95.0, 99.0, ChargeParametersRulesForBatteryVersion1, util::size(ChargeParametersRulesForBatteryVersion1)
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParameters ChargeParametersForBatteryVersion2 = {
|
||||||
|
1, 19, 48, 59, 1664, 4320, UnknownXTableForBatteryVersion2, util::size(UnknownXTableForBatteryVersion2), 95.0, 100.4, ChargeParametersRulesForBatteryVersion2, util::size(ChargeParametersRulesForBatteryVersion2)
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const ChargeParameters ChargeParametersForBatteryVersion0ForFive = {
|
||||||
|
4, 17, 51, 60, 512, 4208, nullptr, 0, 95.0, 99.0, ChargeParametersRulesForBatteryVersion0ForFive, util::size(ChargeParametersRulesForBatteryVersion0ForFive)
|
||||||
|
};
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -55,8 +55,8 @@ namespace ams::powctl::impl {
|
||||||
|
|
||||||
virtual Result GetBatterySocVf(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 GetBatteryFullCapacity(int *out_mah, IDevice *device) = 0;
|
||||||
virtual Result GetBatteryRemainingCapacity(u32 *out_mah, IDevice *device) = 0;
|
virtual Result GetBatteryRemainingCapacity(int *out_mah, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) = 0;
|
virtual Result SetBatteryPercentageMinimumAlertThreshold(IDevice *device, float percentage) = 0;
|
||||||
virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) = 0;
|
virtual Result SetBatteryPercentageMaximumAlertThreshold(IDevice *device, float percentage) = 0;
|
||||||
|
@ -65,25 +65,25 @@ namespace ams::powctl::impl {
|
||||||
virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) = 0;
|
virtual Result GetChargerChargeCurrentState(ChargeCurrentState *out, IDevice *device) = 0;
|
||||||
virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) = 0;
|
virtual Result SetChargerChargeCurrentState(IDevice *device, ChargeCurrentState state) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerFastChargeCurrentLimit(u32 *out_ma, IDevice *device) = 0;
|
virtual Result GetChargerFastChargeCurrentLimit(int *out_ma, IDevice *device) = 0;
|
||||||
virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, u32 ma) = 0;
|
virtual Result SetChargerFastChargeCurrentLimit(IDevice *device, int ma) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerChargeVoltageLimit(u32 *out_mv, IDevice *device) = 0;
|
virtual Result GetChargerChargeVoltageLimit(int *out_mv, IDevice *device) = 0;
|
||||||
virtual Result SetChargerChargeVoltageLimit(IDevice *device, u32 mv) = 0;
|
virtual Result SetChargerChargeVoltageLimit(IDevice *device, int mv) = 0;
|
||||||
|
|
||||||
virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) = 0;
|
virtual Result SetChargerChargerConfiguration(IDevice *device, ChargerConfiguration cfg) = 0;
|
||||||
|
|
||||||
virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) = 0;
|
virtual Result IsChargerHiZEnabled(bool *out, IDevice *device) = 0;
|
||||||
virtual Result SetChargerHiZEnabled(IDevice *device, bool en) = 0;
|
virtual Result SetChargerHiZEnabled(IDevice *device, bool en) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryAverageCurrent(u32 *out_ma, IDevice *device) = 0;
|
virtual Result GetBatteryAverageCurrent(int *out_ma, IDevice *device) = 0;
|
||||||
virtual Result GetBatteryCurrent(u32 *out_ma, IDevice *device) = 0;
|
virtual Result GetBatteryCurrent(int *out_ma, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerInputCurrentLimit(u32 *out_ma, IDevice *device) = 0;
|
virtual Result GetChargerInputCurrentLimit(int *out_ma, IDevice *device) = 0;
|
||||||
virtual Result SetChargerInputCurrentLimit(IDevice *device, u32 ma) = 0;
|
virtual Result SetChargerInputCurrentLimit(IDevice *device, int ma) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerInputVoltageLimit(u32 *out_mv, IDevice *device) = 0;
|
virtual Result GetChargerInputVoltageLimit(int *out_mv, IDevice *device) = 0;
|
||||||
virtual Result SetChargerInputVoltageLimit(IDevice *device, u32 mv) = 0;
|
virtual Result SetChargerInputVoltageLimit(IDevice *device, int mv) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryInternalState(void *dst, size_t *out_size, IDevice *device, size_t dst_size) = 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 SetBatteryInternalState(IDevice *device, const void *src, size_t src_size) = 0;
|
||||||
|
@ -94,12 +94,12 @@ namespace ams::powctl::impl {
|
||||||
virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) = 0;
|
virtual Result IsBatteryI2cShutdownEnabled(bool *out, IDevice *device) = 0;
|
||||||
virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) = 0;
|
virtual Result SetBatteryI2cShutdownEnabled(IDevice *device, bool en) = 0;
|
||||||
|
|
||||||
virtual Result IsBatteryRemoved(bool *out, IDevice *device) = 0;
|
virtual Result IsBatteryPresent(bool *out, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) = 0;
|
virtual Result GetChargerChargerStatus(ChargerStatus *out, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryCycles(u32 *out, IDevice *device) = 0;
|
virtual Result GetBatteryCycles(int *out, IDevice *device) = 0;
|
||||||
virtual Result SetBatteryCycles(IDevice *device, u32 cycles) = 0;
|
virtual Result SetBatteryCycles(IDevice *device, int cycles) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryAge(float *out_percent, IDevice *device) = 0;
|
virtual Result GetBatteryAge(float *out_percent, IDevice *device) = 0;
|
||||||
|
|
||||||
|
@ -109,16 +109,16 @@ namespace ams::powctl::impl {
|
||||||
virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) = 0;
|
virtual Result SetBatteryTemperatureMinimumAlertThreshold(IDevice *device, float c) = 0;
|
||||||
virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) = 0;
|
virtual Result SetBatteryTemperatureMaximumAlertThreshold(IDevice *device, float c) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryVCell(u32 *out_mv, IDevice *device) = 0;
|
virtual Result GetBatteryVCell(int *out_mv, IDevice *device) = 0;
|
||||||
virtual Result GetBatteryAverageVCell(u32 *out_mv, IDevice *device) = 0;
|
virtual Result GetBatteryAverageVCell(int *out_mv, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) = 0;
|
virtual Result GetBatteryAverageVCellTime(TimeSpan *out, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, u32 mv) = 0;
|
virtual Result SetBatteryVoltageMinimumAlertThreshold(IDevice *device, int mv) = 0;
|
||||||
|
|
||||||
virtual Result GetBatteryOpenCircuitVoltage(u32 *out_mv, IDevice *device) = 0;
|
virtual Result GetBatteryOpenCircuitVoltage(int *out_mv, IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, u32 mv) = 0;
|
virtual Result SetBatteryVoltageMaximumAlertThreshold(IDevice *device, int mv) = 0;
|
||||||
|
|
||||||
virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) = 0;
|
virtual Result IsChargerWatchdogTimerEnabled(bool *out, IDevice *device) = 0;
|
||||||
virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) = 0;
|
virtual Result SetChargerWatchdogTimerEnabled(IDevice *device, bool en) = 0;
|
||||||
|
@ -126,11 +126,11 @@ namespace ams::powctl::impl {
|
||||||
virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) = 0;
|
virtual Result SetChargerWatchdogTimerTimeout(IDevice *device, TimeSpan timeout) = 0;
|
||||||
virtual Result ResetChargerWatchdogTimer(IDevice *device) = 0;
|
virtual Result ResetChargerWatchdogTimer(IDevice *device) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerBatteryCompensation(u32 *out_mo, IDevice *device) = 0;
|
virtual Result GetChargerBatteryCompensation(int *out_mo, IDevice *device) = 0;
|
||||||
virtual Result SetChargerBatteryCompensation(IDevice *device, u32 mo) = 0;
|
virtual Result SetChargerBatteryCompensation(IDevice *device, int mo) = 0;
|
||||||
|
|
||||||
virtual Result GetChargerVoltageClamp(u32 *out_mv, IDevice *device) = 0;
|
virtual Result GetChargerVoltageClamp(int *out_mv, IDevice *device) = 0;
|
||||||
virtual Result SetChargerVoltageClamp(IDevice *device, u32 mv) = 0;
|
virtual Result SetChargerVoltageClamp(IDevice *device, int mv) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatterySocVf(out_percent, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatterySocVf(out_percent, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryFullCapacity(u32 *out_mah, Session &session) {
|
Result GetBatteryFullCapacity(int *out_mah, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryFullCapacity(out_mah, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryFullCapacity(out_mah, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryRemainingCapacity(u32 *out_mah, Session &session) {
|
Result GetBatteryRemainingCapacity(int *out_mah, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryPercentageFullThreshold(std::addressof(device), percentage);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryPercentageFullThreshold(std::addressof(device), percentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryAverageCurrent(u32 *out_ma, Session &session) {
|
Result GetBatteryAverageCurrent(int *out_ma, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryAverageCurrent(out_ma, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryAverageCurrent(out_ma, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryCurrent(u32 *out_ma, Session &session) {
|
Result GetBatteryCurrent(int *out_ma, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryI2cShutdownEnabled(std::addressof(device), en);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryI2cShutdownEnabled(std::addressof(device), en);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IsBatteryRemoved(bool *out, Session &session) {
|
Result IsBatteryPresent(bool *out, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -251,10 +251,10 @@ namespace ams::powctl {
|
||||||
auto &device = impl.GetDevice().SafeCastTo<impl::IDevice>();
|
auto &device = impl.GetDevice().SafeCastTo<impl::IDevice>();
|
||||||
|
|
||||||
/* Call into the driver. */
|
/* Call into the driver. */
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().IsBatteryRemoved(out, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().IsBatteryPresent(out, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryCycles(u32 *out, Session &session) {
|
Result GetBatteryCycles(int *out, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryCycles(out, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryCycles(out, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetBatteryCycles(Session &session, u32 cycles) {
|
Result SetBatteryCycles(Session &session, int cycles) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryTemperatureMaximumAlertThreshold(std::addressof(device), c);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryTemperatureMaximumAlertThreshold(std::addressof(device), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryVCell(u32 *out_mv, Session &session) {
|
Result GetBatteryVCell(int *out_mv, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryVCell(out_mv, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryVCell(out_mv, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryAverageVCell(u32 *out_mv, Session &session) {
|
Result GetBatteryAverageVCell(int *out_mv, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryAverageVCellTime(out, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryAverageVCellTime(out, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetBatteryOpenCircuitVoltage(u32 *out_mv, Session &session) {
|
Result GetBatteryOpenCircuitVoltage(int *out_mv, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -408,7 +408,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryOpenCircuitVoltage(out_mv, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetBatteryOpenCircuitVoltage(out_mv, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetBatteryVoltageMinimumAlertThreshold(Session &session, u32 mv) {
|
Result SetBatteryVoltageMinimumAlertThreshold(Session &session, int mv) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryVoltageMinimumAlertThreshold(std::addressof(device), mv);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetBatteryVoltageMinimumAlertThreshold(std::addressof(device), mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetBatteryVoltageMaximumAlertThreshold(Session &session, u32 mv) {
|
Result SetBatteryVoltageMaximumAlertThreshold(Session &session, int mv) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerChargeCurrentState(std::addressof(device), state);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerChargeCurrentState(std::addressof(device), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetChargerFastChargeCurrentLimit(u32 *out_ma, Session &session) {
|
Result GetChargerFastChargeCurrentLimit(int *out_ma, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerFastChargeCurrentLimit(out_ma, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerFastChargeCurrentLimit(out_ma, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetChargerFastChargeCurrentLimit(Session &session, u32 ma) {
|
Result SetChargerFastChargeCurrentLimit(Session &session, int ma) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerFastChargeCurrentLimit(std::addressof(device), ma);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerFastChargeCurrentLimit(std::addressof(device), ma);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetChargerChargeVoltageLimit(u32 *out_mv, Session &session) {
|
Result GetChargerChargeVoltageLimit(int *out_mv, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerChargeVoltageLimit(out_mv, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerChargeVoltageLimit(out_mv, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetChargerChargeVoltageLimit(Session &session, u32 mv) {
|
Result SetChargerChargeVoltageLimit(Session &session, int mv) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerHiZEnabled(std::addressof(device), en);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerHiZEnabled(std::addressof(device), en);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetChargerInputCurrentLimit(u32 *out_ma, Session &session) {
|
Result GetChargerInputCurrentLimit(int *out_ma, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerInputCurrentLimit(out_ma, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerInputCurrentLimit(out_ma, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetChargerInputCurrentLimit(Session &session, u32 ma) {
|
Result SetChargerInputCurrentLimit(Session &session, int ma) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerInputCurrentLimit(std::addressof(device), ma);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerInputCurrentLimit(std::addressof(device), ma);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetChargerInputVoltageLimit(u32 *out_mv, Session &session) {
|
Result GetChargerInputVoltageLimit(int *out_mv, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerInputVoltageLimit(out_mv, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerInputVoltageLimit(out_mv, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetChargerInputVoltageLimit(Session &session, u32 mv) {
|
Result SetChargerInputVoltageLimit(Session &session, int mv) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ namespace ams::powctl {
|
||||||
|
|
||||||
Result ResetChargerWatchdogTimer(Session &session);
|
Result ResetChargerWatchdogTimer(Session &session);
|
||||||
|
|
||||||
Result GetChargerBatteryCompensation(u32 *out_mo, Session &session) {
|
Result GetChargerBatteryCompensation(int *out_mo, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerBatteryCompensation(out_mo, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerBatteryCompensation(out_mo, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetChargerBatteryCompensation(Session &session, u32 mo) {
|
Result SetChargerBatteryCompensation(Session &session, int mo) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerBatteryCompensation(std::addressof(device), mo);
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().SetChargerBatteryCompensation(std::addressof(device), mo);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetChargerVoltageClamp(u32 *out_mv, Session &session) {
|
Result GetChargerVoltageClamp(int *out_mv, Session &session) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ namespace ams::powctl {
|
||||||
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerVoltageClamp(out_mv, std::addressof(device));
|
return device.GetDriver().SafeCastTo<impl::IPowerControlDriver>().GetChargerVoltageClamp(out_mv, std::addressof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetChargerVoltageClamp(Session &session, u32 mv) {
|
Result SetChargerVoltageClamp(Session &session, int mv) {
|
||||||
/* Get the session impl. */
|
/* Get the session impl. */
|
||||||
auto &impl = GetOpenSessionImpl(session);
|
auto &impl = GetOpenSessionImpl(session);
|
||||||
|
|
||||||
|
|
|
@ -1,299 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#include "boot_battery_driver.hpp"
|
|
||||||
#include "boot_calibration.hpp"
|
|
||||||
#include "boot_i2c_utils.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
|
||||||
|
|
||||||
/* Include configuration into anonymous namespace. */
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
#include "boot_battery_parameters.inc"
|
|
||||||
|
|
||||||
const Max17050Parameters *GetBatteryParameters() {
|
|
||||||
const u32 battery_version = GetBatteryVersion();
|
|
||||||
const u32 battery_vendor = GetBatteryVendor();
|
|
||||||
|
|
||||||
if (battery_version == 2) {
|
|
||||||
if (battery_vendor == 'M') {
|
|
||||||
return &Max17050Params2M;
|
|
||||||
} else {
|
|
||||||
return &Max17050Params2;
|
|
||||||
}
|
|
||||||
} else if (battery_version == 1) {
|
|
||||||
return &Max17050Params1;
|
|
||||||
} else {
|
|
||||||
switch (battery_vendor) {
|
|
||||||
case 'M':
|
|
||||||
return &Max17050ParamsM;
|
|
||||||
case 'R':
|
|
||||||
return &Max17050ParamsR;
|
|
||||||
case 'A':
|
|
||||||
default:
|
|
||||||
return &Max17050ParamsA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::Read(u8 addr, u16 *out) {
|
|
||||||
return ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::Write(u8 addr, u16 val) {
|
|
||||||
return WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::ReadWrite(u8 addr, u16 mask, u16 val) {
|
|
||||||
u16 cur_val;
|
|
||||||
R_TRY(this->Read(addr, &cur_val));
|
|
||||||
|
|
||||||
const u16 new_val = (cur_val & ~mask) | val;
|
|
||||||
R_TRY(this->Write(addr, new_val));
|
|
||||||
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BatteryDriver::WriteValidate(u8 addr, u16 val) {
|
|
||||||
/* Nintendo doesn't seem to check errors when doing this? */
|
|
||||||
/* It's probably okay, since the value does get validated. */
|
|
||||||
/* That said, we will validate the read to avoid uninit data problems. */
|
|
||||||
this->Write(addr, val);
|
|
||||||
svcSleepThread(3'000'000ul);
|
|
||||||
|
|
||||||
u16 new_val;
|
|
||||||
return R_SUCCEEDED(this->Read(addr, &new_val)) && new_val == val;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BatteryDriver::IsPowerOnReset() {
|
|
||||||
/* N doesn't check result... */
|
|
||||||
u16 val = 0;
|
|
||||||
this->Read(Max17050Status, &val);
|
|
||||||
return (val & 0x0002) == 0x0002;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::LockVfSoc() {
|
|
||||||
return this->Write(Max17050SocVfAccess, 0x0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::UnlockVfSoc() {
|
|
||||||
return this->Write(Max17050SocVfAccess, 0x0080);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::LockModelTable() {
|
|
||||||
R_TRY(this->Write(Max17050ModelAccess0, 0x0000));
|
|
||||||
R_TRY(this->Write(Max17050ModelAccess1, 0x0000));
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::UnlockModelTable() {
|
|
||||||
R_TRY(this->Write(Max17050ModelAccess0, 0x0059));
|
|
||||||
R_TRY(this->Write(Max17050ModelAccess1, 0x00C4));
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::SetModelTable(const u16 *model_table) {
|
|
||||||
for (size_t i = 0; i < Max17050ModelChrTblSize; i++) {
|
|
||||||
R_TRY(this->Write(Max17050ModelChrTblStart + i, model_table[i]));
|
|
||||||
}
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BatteryDriver::IsModelTableLocked() {
|
|
||||||
bool locked = true;
|
|
||||||
|
|
||||||
u16 cur_val = 0;
|
|
||||||
for (size_t i = 0; i < Max17050ModelChrTblSize; i++) {
|
|
||||||
this->Read(Max17050ModelChrTblStart + i, &cur_val);
|
|
||||||
locked &= (cur_val == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return locked;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BatteryDriver::IsModelTableSet(const u16 *model_table) {
|
|
||||||
bool set = true;
|
|
||||||
|
|
||||||
u16 cur_val = 0;
|
|
||||||
for (size_t i = 0; i < Max17050ModelChrTblSize; i++) {
|
|
||||||
this->Read(Max17050ModelChrTblStart + i, &cur_val);
|
|
||||||
set &= (cur_val == model_table[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::InitializeBatteryParameters() {
|
|
||||||
const Max17050Parameters *params = GetBatteryParameters();
|
|
||||||
|
|
||||||
if (IsPowerOnReset()) {
|
|
||||||
/* Do initial config. */
|
|
||||||
R_TRY(this->ReadWrite(Max17050MiscCfg, 0x8000, 0x8000));
|
|
||||||
|
|
||||||
svcSleepThread(500'000'000ul);
|
|
||||||
|
|
||||||
R_TRY(this->Write(Max17050Config, 0x7210));
|
|
||||||
R_TRY(this->Write(Max17050FilterCfg, 0x8784));
|
|
||||||
R_TRY(this->Write(Max17050RelaxCfg, params->relaxcfg));
|
|
||||||
R_TRY(this->Write(Max17050LearnCfg, 0x2603));
|
|
||||||
R_TRY(this->Write(Max17050FullSocThr, params->fullsocthr));
|
|
||||||
R_TRY(this->Write(Max17050IAvgEmpty, params->iavgempty));
|
|
||||||
|
|
||||||
/* Unlock model table, write model table. */
|
|
||||||
do {
|
|
||||||
R_TRY(this->UnlockModelTable());
|
|
||||||
R_TRY(this->SetModelTable(params->modeltbl));
|
|
||||||
} while (!this->IsModelTableSet(params->modeltbl));
|
|
||||||
|
|
||||||
/* Lock model table. */
|
|
||||||
size_t lock_i = 0;
|
|
||||||
while (true) {
|
|
||||||
lock_i++;
|
|
||||||
R_TRY(this->LockModelTable());
|
|
||||||
|
|
||||||
if (this->IsModelTableLocked()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lock_i >= 8) {
|
|
||||||
/* This is regarded as guaranteed success. */
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write custom parameters. */
|
|
||||||
while (!this->WriteValidate(Max17050RComp0, params->rcomp0)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050TempCo, params->tempco)) { /* ... */ }
|
|
||||||
|
|
||||||
R_TRY(this->Write(Max17050IChgTerm, params->ichgterm));
|
|
||||||
R_TRY(this->Write(Max17050TGain, params->tgain));
|
|
||||||
R_TRY(this->Write(Max17050TOff, params->toff));
|
|
||||||
|
|
||||||
while (!this->WriteValidate(Max17050VEmpty, params->vempty)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050QResidual00, params->qresidual00)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050QResidual10, params->qresidual10)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050QResidual20, params->qresidual20)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050QResidual30, params->qresidual30)) { /* ... */ }
|
|
||||||
|
|
||||||
|
|
||||||
/* Write full capacity parameters. */
|
|
||||||
while (!this->WriteValidate(Max17050FullCap, params->fullcap)) { /* ... */ }
|
|
||||||
R_TRY(this->Write(Max17050DesignCap, params->vffullcap));
|
|
||||||
while (!this->WriteValidate(Max17050FullCapNom, params->vffullcap)) { /* ... */ }
|
|
||||||
|
|
||||||
svcSleepThread(350'000'000ul);
|
|
||||||
|
|
||||||
/* Write VFSOC to VFSOC 0. */
|
|
||||||
u16 vfsoc, qh;
|
|
||||||
{
|
|
||||||
R_TRY(this->Read(Max17050SocVf, &vfsoc));
|
|
||||||
R_TRY(this->UnlockVfSoc());
|
|
||||||
R_TRY(this->Write(Max17050SocVf0, vfsoc));
|
|
||||||
R_TRY(this->Read(Max17050Qh, &qh));
|
|
||||||
R_TRY(this->Write(Max17050Qh0, qh));
|
|
||||||
R_TRY(this->LockVfSoc());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write cycles. */
|
|
||||||
while (!this->WriteValidate(Max17050Cycles, 0x0060)) { /* ... */ }
|
|
||||||
|
|
||||||
/* Load new capacity parameters. */
|
|
||||||
const u16 remcap = static_cast<u16>((vfsoc * params->vffullcap) / 0x6400);
|
|
||||||
const u16 repcap = static_cast<u16>(remcap * (params->fullcap / params->vffullcap));
|
|
||||||
const u16 dqacc = params->vffullcap / 0x10;
|
|
||||||
while (!this->WriteValidate(Max17050RemCapMix, remcap)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050RemCapRep, repcap)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050DPAcc, 0x0C80)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050DQAcc, dqacc)) { /* ... */ }
|
|
||||||
while (!this->WriteValidate(Max17050FullCap, params->fullcap)) { /* ... */ }
|
|
||||||
R_TRY(this->Write(Max17050DesignCap, params->vffullcap));
|
|
||||||
while (!this->WriteValidate(Max17050FullCapNom, params->vffullcap)) { /* ... */ }
|
|
||||||
R_TRY(this->Write(Max17050SocRep, vfsoc));
|
|
||||||
|
|
||||||
/* Finish initialization. */
|
|
||||||
{
|
|
||||||
u16 status;
|
|
||||||
R_TRY(this->Read(Max17050Status, &status));
|
|
||||||
while (!this->WriteValidate(Max17050Status, status & 0xFFFD)) { /* ... */ }
|
|
||||||
}
|
|
||||||
R_TRY(this->Write(Max17050CGain, 0x7FFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::IsBatteryRemoved(bool *out) {
|
|
||||||
/* N doesn't check result, but we will. */
|
|
||||||
u16 val = 0;
|
|
||||||
R_TRY(this->Read(Max17050Status, &val));
|
|
||||||
*out = (val & 0x0008) == 0x0008;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::GetTemperature(double *out) {
|
|
||||||
u16 val = 0;
|
|
||||||
R_TRY(this->Read(Max17050Temperature, &val));
|
|
||||||
*out = static_cast<double>(val) * double(0.00390625);
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::GetAverageVCell(u32 *out) {
|
|
||||||
u16 val = 0;
|
|
||||||
R_TRY(this->Read(Max17050AverageVCell, &val));
|
|
||||||
*out = (625 * u32(val >> 3)) / 1000;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::GetSocRep(double *out) {
|
|
||||||
u16 val = 0;
|
|
||||||
R_TRY(this->Read(Max17050SocRep, &val));
|
|
||||||
*out = static_cast<double>(val) * double(0.00390625);
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::GetBatteryPercentage(size_t *out) {
|
|
||||||
double raw_charge;
|
|
||||||
R_TRY(this->GetSocRep(&raw_charge));
|
|
||||||
int converted_percentage = (((raw_charge - 3.93359375) * 98.0) / 94.2304688) + 2.0;
|
|
||||||
if (converted_percentage < 1) {
|
|
||||||
*out = 1;
|
|
||||||
} else if (converted_percentage > 100) {
|
|
||||||
*out = 100;
|
|
||||||
} else {
|
|
||||||
*out = static_cast<size_t>(converted_percentage);
|
|
||||||
}
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::SetShutdownTimer() {
|
|
||||||
return this->Write(Max17050ShdnTimer, 0xE000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::GetShutdownEnabled(bool *out) {
|
|
||||||
u16 val = 0;
|
|
||||||
R_TRY(this->Read(Max17050Config, &val));
|
|
||||||
*out = (val & 0x0040) != 0;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result BatteryDriver::SetShutdownEnabled(bool enabled) {
|
|
||||||
return this->ReadWrite(Max17050Config, 0x0040, enabled ? 0x0040 : 0x0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -14,45 +14,60 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
class BatteryDriver {
|
class BatteryDriver {
|
||||||
private:
|
private:
|
||||||
i2c::driver::I2cSession i2c_session;
|
powctl::Session battery_session;
|
||||||
public:
|
public:
|
||||||
BatteryDriver() {
|
BatteryDriver() : battery_session() {
|
||||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max17050));
|
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(this->battery_session), powctl::DeviceCode_Max17050, ddsf::AccessMode_ReadWrite));
|
||||||
}
|
}
|
||||||
|
|
||||||
~BatteryDriver() {
|
~BatteryDriver() {
|
||||||
i2c::driver::CloseSession(this->i2c_session);
|
powctl::CloseSession(this->battery_session);
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
Result Read(u8 addr, u16 *out_data);
|
|
||||||
Result Write(u8 addr, u16 val);
|
|
||||||
Result ReadWrite(u8 addr, u16 mask, u16 val);
|
|
||||||
bool WriteValidate(u8 addr, u16 val);
|
|
||||||
|
|
||||||
bool IsPowerOnReset();
|
|
||||||
Result LockVfSoc();
|
|
||||||
Result UnlockVfSoc();
|
|
||||||
Result LockModelTable();
|
|
||||||
Result UnlockModelTable();
|
|
||||||
bool IsModelTableLocked();
|
|
||||||
Result SetModelTable(const u16 *model_table);
|
|
||||||
bool IsModelTableSet(const u16 *model_table);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Result InitializeBatteryParameters();
|
Result IsBatteryRemoved(bool *out) {
|
||||||
Result IsBatteryRemoved(bool *out);
|
bool present;
|
||||||
Result GetTemperature(double *out);
|
R_TRY(powctl::IsBatteryPresent(std::addressof(present), this->battery_session));
|
||||||
Result GetAverageVCell(u32 *out);
|
|
||||||
Result GetSocRep(double *out);
|
return present == false;
|
||||||
Result GetBatteryPercentage(size_t *out);
|
}
|
||||||
Result SetShutdownTimer();
|
|
||||||
Result GetShutdownEnabled(bool *out);
|
Result GetSocRep(float *out) {
|
||||||
Result SetShutdownEnabled(bool enabled);
|
return powctl::GetBatterySocRep(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetAverageVCell(int *out) {
|
||||||
|
return powctl::GetBatteryAverageVCell(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetOpenCircuitVoltage(int *out) {
|
||||||
|
return powctl::GetBatteryOpenCircuitVoltage(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetAverageCurrent(int *out) {
|
||||||
|
return powctl::GetBatteryAverageCurrent(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetCurrent(int *out) {
|
||||||
|
return powctl::GetBatteryCurrent(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetTemperature(float *out) {
|
||||||
|
return powctl::GetBatteryTemperature(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IsI2cShutdownEnabled(bool *out) {
|
||||||
|
return powctl::IsBatteryI2cShutdownEnabled(out, this->battery_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetI2cShutdownEnabled(bool en) {
|
||||||
|
return powctl::SetBatteryI2cShutdownEnabled(this->battery_session, en);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,9 @@ namespace ams::boot {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Pull in icon definitions. */
|
/* Pull in icon definitions. */
|
||||||
#include "boot_battery_icon_low.inc"
|
#include "boot_battery_icon_low.inc"
|
||||||
#include "boot_battery_icon_charging.inc"
|
#include "boot_battery_icon_charging.inc"
|
||||||
#include "boot_battery_icon_charging_red.inc"
|
#include "boot_battery_icon_charging_red.inc"
|
||||||
|
|
||||||
/* Helpers. */
|
/* Helpers. */
|
||||||
void FillBatteryMeter(u32 *icon, const size_t icon_w, const size_t icon_h, const size_t meter_x, const size_t meter_y, const size_t meter_w, const size_t meter_h, const size_t fill_w) {
|
void FillBatteryMeter(u32 *icon, const size_t icon_w, const size_t icon_h, const size_t meter_x, const size_t meter_y, const size_t meter_w, const size_t meter_h, const size_t fill_w) {
|
||||||
|
@ -54,12 +54,12 @@ namespace ams::boot {
|
||||||
{
|
{
|
||||||
/* Low battery icon is shown for 5 seconds. */
|
/* Low battery icon is shown for 5 seconds. */
|
||||||
ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery);
|
ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery);
|
||||||
svcSleepThread(5'000'000'000ul);
|
os::SleepThread(TimeSpan::FromSeconds(5));
|
||||||
}
|
}
|
||||||
FinalizeDisplay();
|
FinalizeDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartShowChargingIcon(size_t battery_percentage, bool wait) {
|
void StartShowChargingIcon(int battery_percentage, bool wait) {
|
||||||
const bool is_red = battery_percentage <= 15;
|
const bool is_red = battery_percentage <= 15;
|
||||||
|
|
||||||
const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX;
|
const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX;
|
||||||
|
@ -70,7 +70,7 @@ namespace ams::boot {
|
||||||
const size_t IconMeterY = is_red ? ChargingRedBatteryMeterY : ChargingBatteryMeterY;
|
const size_t IconMeterY = is_red ? ChargingRedBatteryMeterY : ChargingBatteryMeterY;
|
||||||
const size_t IconMeterW = is_red ? ChargingRedBatteryMeterW : ChargingBatteryMeterW;
|
const size_t IconMeterW = is_red ? ChargingRedBatteryMeterW : ChargingBatteryMeterW;
|
||||||
const size_t IconMeterH = is_red ? ChargingRedBatteryMeterH : ChargingBatteryMeterH;
|
const size_t IconMeterH = is_red ? ChargingRedBatteryMeterH : ChargingBatteryMeterH;
|
||||||
const size_t MeterFillW = static_cast<size_t>(IconMeterW * (1.0 - (0.0404 + 0.0096 * battery_percentage)) + 0.5);
|
const size_t MeterFillW = static_cast<size_t>(IconMeterW * (1.0 - (0.0404 + 0.0096 * static_cast<double>(battery_percentage))) + 0.5);
|
||||||
|
|
||||||
/* Create stack buffer, copy icon into it, draw fill meter, draw. */
|
/* Create stack buffer, copy icon into it, draw fill meter, draw. */
|
||||||
{
|
{
|
||||||
|
@ -84,7 +84,7 @@ namespace ams::boot {
|
||||||
|
|
||||||
/* Wait for 2 seconds if we're supposed to. */
|
/* Wait for 2 seconds if we're supposed to. */
|
||||||
if (wait) {
|
if (wait) {
|
||||||
svcSleepThread(2'000'000'000ul);
|
os::SleepThread(TimeSpan::FromSeconds(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,21 @@
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
#include "boot_display.hpp"
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
/* Battery Display utilities. */
|
/* Battery Display utilities. */
|
||||||
void ShowLowBatteryIcon();
|
void ShowLowBatteryIcon();
|
||||||
void StartShowChargingIcon(size_t battery_percentage, bool wait);
|
void StartShowChargingIcon(int battery_percentage, bool wait);
|
||||||
void EndShowChargingIcon();
|
void EndShowChargingIcon();
|
||||||
|
|
||||||
|
inline void StartShowChargingIcon(int battery_percentage) {
|
||||||
|
return StartShowChargingIcon(battery_percentage, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void StartShowLowBatteryChargingIcon() {
|
||||||
|
return StartShowChargingIcon(1, false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
constexpr u8 Max17050Status = 0x00;
|
|
||||||
constexpr u8 Max17050VAlrtThreshold = 0x01;
|
|
||||||
constexpr u8 Max17050TAlrtThreshold = 0x02;
|
|
||||||
constexpr u8 Max17050SocAlrtThreshold = 0x03;
|
|
||||||
constexpr u8 Max17050AtRate = 0x04;
|
|
||||||
constexpr u8 Max17050RemCapRep = 0x05;
|
|
||||||
constexpr u8 Max17050SocRep = 0x06;
|
|
||||||
constexpr u8 Max17050Age = 0x07;
|
|
||||||
constexpr u8 Max17050Temperature = 0x08;
|
|
||||||
constexpr u8 Max17050VCell = 0x09;
|
|
||||||
constexpr u8 Max17050Current = 0x0A;
|
|
||||||
constexpr u8 Max17050AverageCurrent = 0x0B;
|
|
||||||
|
|
||||||
constexpr u8 Max17050SocMix = 0x0D;
|
|
||||||
constexpr u8 Max17050SocAv = 0x0E;
|
|
||||||
constexpr u8 Max17050RemCapMix = 0x0F;
|
|
||||||
constexpr u8 Max17050FullCap = 0x10;
|
|
||||||
constexpr u8 Max17050Tte = 0x11;
|
|
||||||
constexpr u8 Max17050QResidual00 = 0x12;
|
|
||||||
constexpr u8 Max17050FullSocThr = 0x13;
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050AverageTemp = 0x16;
|
|
||||||
constexpr u8 Max17050Cycles = 0x17;
|
|
||||||
constexpr u8 Max17050DesignCap = 0x18;
|
|
||||||
constexpr u8 Max17050AverageVCell = 0x19;
|
|
||||||
constexpr u8 Max17050MaxMinTemp = 0x1A;
|
|
||||||
constexpr u8 Max17050MaxMinVoltage = 0x1B;
|
|
||||||
constexpr u8 Max17050MaxMinCurrent = 0x1C;
|
|
||||||
constexpr u8 Max17050Config = 0x1D;
|
|
||||||
constexpr u8 Max17050IChgTerm = 0x1E;
|
|
||||||
constexpr u8 Max17050RemCapAv = 0x1F;
|
|
||||||
|
|
||||||
constexpr u8 Max17050Version = 0x21;
|
|
||||||
constexpr u8 Max17050QResidual10 = 0x22;
|
|
||||||
constexpr u8 Max17050FullCapNom = 0x23;
|
|
||||||
constexpr u8 Max17050TempNom = 0x24;
|
|
||||||
constexpr u8 Max17050TempLim = 0x25;
|
|
||||||
|
|
||||||
constexpr u8 Max17050Ain = 0x27;
|
|
||||||
constexpr u8 Max17050LearnCfg = 0x28;
|
|
||||||
constexpr u8 Max17050FilterCfg = 0x29;
|
|
||||||
constexpr u8 Max17050RelaxCfg = 0x2A;
|
|
||||||
constexpr u8 Max17050MiscCfg = 0x2B;
|
|
||||||
constexpr u8 Max17050TGain = 0x2C;
|
|
||||||
constexpr u8 Max17050TOff = 0x2D;
|
|
||||||
constexpr u8 Max17050CGain = 0x2E;
|
|
||||||
constexpr u8 Max17050COff = 0x2F;
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050QResidual20 = 0x32;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050IAvgEmpty = 0x36;
|
|
||||||
constexpr u8 Max17050FCtc = 0x37;
|
|
||||||
constexpr u8 Max17050RComp0 = 0x38;
|
|
||||||
constexpr u8 Max17050TempCo = 0x39;
|
|
||||||
constexpr u8 Max17050VEmpty = 0x3A;
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050FStat = 0x3D;
|
|
||||||
constexpr u8 Max17050Timer = 0x3E;
|
|
||||||
constexpr u8 Max17050ShdnTimer = 0x3F;
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050QResidual30 = 0x42;
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050DQAcc = 0x45;
|
|
||||||
constexpr u8 Max17050DPAcc = 0x46;
|
|
||||||
|
|
||||||
constexpr u8 Max17050SocVf0 = 0x48;
|
|
||||||
|
|
||||||
constexpr u8 Max17050Qh0 = 0x4C;
|
|
||||||
constexpr u8 Max17050Qh = 0x4D;
|
|
||||||
|
|
||||||
constexpr u8 Max17050SocVfAccess = 0x60;
|
|
||||||
|
|
||||||
constexpr u8 Max17050ModelAccess0 = 0x62;
|
|
||||||
constexpr u8 Max17050ModelAccess1 = 0x63;
|
|
||||||
|
|
||||||
constexpr u8 Max17050ModelChrTblStart = 0x80;
|
|
||||||
constexpr u8 Max17050ModelChrTblEnd = 0xB0;
|
|
||||||
|
|
||||||
|
|
||||||
constexpr u8 Max17050VFocV = 0xFB;
|
|
||||||
constexpr u8 Max17050SocVf = 0xFF;
|
|
||||||
|
|
||||||
constexpr size_t Max17050ModelChrTblSize = Max17050ModelChrTblEnd - Max17050ModelChrTblStart;
|
|
||||||
|
|
||||||
struct Max17050Parameters {
|
|
||||||
u16 relaxcfg;
|
|
||||||
u16 rcomp0;
|
|
||||||
u16 tempco;
|
|
||||||
u16 ichgterm;
|
|
||||||
u16 tgain;
|
|
||||||
u16 toff;
|
|
||||||
u16 vempty;
|
|
||||||
u16 qresidual00;
|
|
||||||
u16 qresidual10;
|
|
||||||
u16 qresidual20;
|
|
||||||
u16 qresidual30;
|
|
||||||
u16 fullcap;
|
|
||||||
u16 vffullcap;
|
|
||||||
u16 modeltbl[Max17050ModelChrTblSize];
|
|
||||||
u16 fullsocthr;
|
|
||||||
u16 iavgempty;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(Max17050Parameters) == 0x7E, "Max17050Parameters definition!");
|
|
||||||
|
|
||||||
constexpr Max17050Parameters Max17050ParamsA = {
|
|
||||||
0x203B, /* relaxcfg */
|
|
||||||
0x0053, /* rcomp0 */
|
|
||||||
0x1C22, /* tempco */
|
|
||||||
0x0333, /* ichgterm */
|
|
||||||
0xE1F6, /* tgain */
|
|
||||||
0x2BF2, /* toff */
|
|
||||||
0xA05F, /* vempty */
|
|
||||||
0x5786, /* qresidual00 */
|
|
||||||
0x3184, /* qresidual10 */
|
|
||||||
0x1E00, /* qresidual20 */
|
|
||||||
0x1602, /* qresidual30 */
|
|
||||||
0x2476, /* fullcap */
|
|
||||||
0x2476, /* vffullcap */
|
|
||||||
{ /* modeltbl */
|
|
||||||
0x9FF0, 0xAD30, 0xB5D0, 0xB9C0, 0xBAD0, 0xBBE0, 0xBC30, 0xBC90,
|
|
||||||
0xBCE0, 0xBD40, 0xBE70, 0xC0E0, 0xC4E0, 0xC890, 0xCC90, 0xD0F0,
|
|
||||||
0x0170, 0x0480, 0x0590, 0x0BE0, 0x0A00, 0x3C00, 0x3810, 0x3A00,
|
|
||||||
0x3A30, 0x19F0, 0x0EF0, 0x0AF0, 0x0BD0, 0x07F0, 0x06F0, 0x06F0,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
},
|
|
||||||
0x5F00, /* fullsocthr */
|
|
||||||
0x1D2A /* iavgempty */
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr Max17050Parameters Max17050ParamsM = {
|
|
||||||
0x203B, /* relaxcfg */
|
|
||||||
0x0085, /* rcomp0 */
|
|
||||||
0x1625, /* tempco */
|
|
||||||
0x0333, /* ichgterm */
|
|
||||||
0xE1F6, /* tgain */
|
|
||||||
0x2BF2, /* toff */
|
|
||||||
0xA05F, /* vempty */
|
|
||||||
0x3100, /* qresidual00 */
|
|
||||||
0x1B00, /* qresidual10 */
|
|
||||||
0x1000, /* qresidual20 */
|
|
||||||
0x0C81, /* qresidual30 */
|
|
||||||
0x227A, /* fullcap */
|
|
||||||
0x227A, /* vffullcap */
|
|
||||||
{ /* modeltbl */
|
|
||||||
0xA340, 0xB840, 0xB900, 0xBB70, 0xBC90, 0xBD20, 0xBDC0, 0xBEA0,
|
|
||||||
0xBF70, 0xC030, 0xC210, 0xC3F0, 0xC800, 0xC9E0, 0xCCA0, 0xD090,
|
|
||||||
0x0160, 0x3800, 0x0800, 0x1E00, 0x2550, 0x3060, 0x15D0, 0x1810,
|
|
||||||
0x1490, 0x0B80, 0x0BF0, 0x0AF0, 0x0CB0, 0x06F0, 0x09D0, 0x09D0,
|
|
||||||
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
|
|
||||||
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
|
|
||||||
},
|
|
||||||
0x5F00, /* fullsocthr */
|
|
||||||
0x1D2A /* iavgempty */
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr Max17050Parameters Max17050ParamsR = {
|
|
||||||
0x203B, /* relaxcfg */
|
|
||||||
0x0048, /* rcomp0 */
|
|
||||||
0x2034, /* tempco */
|
|
||||||
0x0333, /* ichgterm */
|
|
||||||
0xE1F6, /* tgain */
|
|
||||||
0x2BF2, /* toff */
|
|
||||||
0xA05F, /* vempty */
|
|
||||||
0x5A00, /* qresidual00 */
|
|
||||||
0x3B00, /* qresidual10 */
|
|
||||||
0x0F80, /* qresidual20 */
|
|
||||||
0x0B02, /* qresidual30 */
|
|
||||||
0x2466, /* fullcap */
|
|
||||||
0x2466, /* vffullcap */
|
|
||||||
{ /* modeltbl */
|
|
||||||
0x9C50, 0xAD90, 0xB270, 0xB6A0, 0xB8F0, 0xBB10, 0xBC00, 0xBD00,
|
|
||||||
0xBD70, 0xBE70, 0xBF50, 0xC1F0, 0xC380, 0xC590, 0xC8E0, 0xD0B0,
|
|
||||||
0x00D0, 0x0150, 0x0300, 0x0D00, 0x0E00, 0x1900, 0x2AC0, 0x2830,
|
|
||||||
0x1760, 0x18F0, 0x0DF0, 0x0BC0, 0x0DF0, 0x0BF0, 0x06F0, 0x06F0,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
},
|
|
||||||
0x5F00, /* fullsocthr */
|
|
||||||
0x1D2A /* iavgempty */
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr Max17050Parameters Max17050Params1 = {
|
|
||||||
0x203B, /* relaxcfg */
|
|
||||||
0x0040, /* rcomp0 */
|
|
||||||
0x1624, /* tempco */
|
|
||||||
0x0333, /* ichgterm */
|
|
||||||
0xE1F6, /* tgain */
|
|
||||||
0x2BF2, /* toff */
|
|
||||||
0xA05F, /* vempty */
|
|
||||||
0x4690, /* qresidual00 */
|
|
||||||
0x2605, /* qresidual10 */
|
|
||||||
0x1605, /* qresidual20 */
|
|
||||||
0x0F05, /* qresidual30 */
|
|
||||||
0x1AE4, /* fullcap */
|
|
||||||
0x1AE4, /* vffullcap */
|
|
||||||
{ /* modeltbl */
|
|
||||||
0x8B50, 0x9C20, 0xACF0, 0xB160, 0xB3A0, 0xB5B0, 0xB950, 0xBBE0,
|
|
||||||
0xBDC0, 0xBEF0, 0xC140, 0xC250, 0xC600, 0xC960, 0xCCE0, 0xD060,
|
|
||||||
0x0070, 0x00F0, 0x0440, 0x0400, 0x0500, 0x0400, 0x0D00, 0x3270,
|
|
||||||
0x0FB0, 0x0AF0, 0x10F0, 0x0CE0, 0x09E0, 0x07F0, 0x06F0, 0x06F0,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
},
|
|
||||||
0x5F00, /* fullsocthr */
|
|
||||||
0x1584 /* iavgempty */
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr Max17050Parameters Max17050Params2 = {
|
|
||||||
0x203B, /* relaxcfg */
|
|
||||||
0x004A, /* rcomp0 */
|
|
||||||
0x1D23, /* tempco */
|
|
||||||
0x0333, /* ichgterm */
|
|
||||||
0xE1F6, /* tgain */
|
|
||||||
0x2BF2, /* toff */
|
|
||||||
0xA05F, /* vempty */
|
|
||||||
0x4000, /* qresidual00 */
|
|
||||||
0x1E80, /* qresidual10 */
|
|
||||||
0x0D83, /* qresidual20 */
|
|
||||||
0x0783, /* qresidual30 */
|
|
||||||
0x1C20, /* fullcap */
|
|
||||||
0x1C20, /* vffullcap */
|
|
||||||
{ /* modeltbl */
|
|
||||||
0x8040, 0x9A30, 0xB430, 0xB770, 0xBAB0, 0xBBC0, 0xBD00, 0xBE50,
|
|
||||||
0xBF70, 0xC0D0, 0xC300, 0xC590, 0xC960, 0xCD40, 0xD1F0, 0xD5C0,
|
|
||||||
0x0040, 0x0060, 0x0510, 0x0D30, 0x16C0, 0x2160, 0x1380, 0x1A10,
|
|
||||||
0x0EC0, 0x0CE0, 0x08F0, 0x0940, 0x0920, 0x06F0, 0x06C0, 0x06C0,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
},
|
|
||||||
0x5500, /* fullsocthr */
|
|
||||||
0x1680 /* iavgempty */
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr Max17050Parameters Max17050Params2M = {
|
|
||||||
0x203B, /* relaxcfg */
|
|
||||||
0x0049, /* rcomp0 */
|
|
||||||
0x222A, /* tempco */
|
|
||||||
0x0333, /* ichgterm */
|
|
||||||
0xE1F6, /* tgain */
|
|
||||||
0x2BF2, /* toff */
|
|
||||||
0xA05F, /* vempty */
|
|
||||||
0x4F00, /* qresidual00 */
|
|
||||||
0x2680, /* qresidual10 */
|
|
||||||
0x1205, /* qresidual20 */
|
|
||||||
0x0C87, /* qresidual30 */
|
|
||||||
0x1C68, /* fullcap */
|
|
||||||
0x1C68, /* vffullcap */
|
|
||||||
{ /* modeltbl */
|
|
||||||
0x8E40, 0xB570, 0xB8F0, 0xBB00, 0xBC20, 0xBCC0, 0xBE30, 0xBFE0,
|
|
||||||
0xC200, 0xC400, 0xC720, 0xCB50, 0xCF00, 0xD100, 0xD480, 0xD5C0,
|
|
||||||
0x00C0, 0x0C00, 0x0A10, 0x1800, 0x2C00, 0x1C10, 0x12D0, 0x09F0,
|
|
||||||
0x0AF0, 0x0850, 0x09F0, 0x06F0, 0x06B0, 0x07E0, 0x01D0, 0x01D0,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
|
|
||||||
},
|
|
||||||
0x5500, /* fullsocthr */
|
|
||||||
0x16B9 /* iavgempty */
|
|
||||||
};
|
|
|
@ -23,29 +23,29 @@ namespace ams::boot {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Globals. */
|
/* Globals. */
|
||||||
u32 g_boot_reason = 0;
|
constinit spl::BootReason g_boot_reason = spl::BootReason_Unknown;
|
||||||
bool g_detected_boot_reason = false;
|
constinit bool g_detected_boot_reason = false;
|
||||||
|
|
||||||
/* Helpers. */
|
/* Helpers. */
|
||||||
u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
|
spl::BootReason DetectBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
|
||||||
if (power_intr & 0x08) {
|
if (power_intr & 0x08) {
|
||||||
return 2;
|
return spl::BootReason_OnKey;
|
||||||
}
|
}
|
||||||
if (rtc_intr & 0x02) {
|
if (rtc_intr & 0x02) {
|
||||||
return 3;
|
return spl::BootReason_RtcAlarm1;
|
||||||
}
|
}
|
||||||
if (power_intr & 0x80) {
|
if (power_intr & 0x80) {
|
||||||
return 1;
|
return spl::BootReason_AcOk;
|
||||||
}
|
}
|
||||||
if (rtc_intr & 0x04) {
|
if (rtc_intr & 0x04) {
|
||||||
if (nv_erc != 0x80 && !spl::IsRecoveryBoot()) {
|
if (nv_erc != 0x80 && !spl::IsRecoveryBoot()) {
|
||||||
return 4;
|
return spl::BootReason_RtcAlarm2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((nv_erc & 0x40) && ac_ok) {
|
if ((nv_erc & 0x40) && ac_ok) {
|
||||||
return 1;
|
return spl::BootReason_AcOk;
|
||||||
}
|
}
|
||||||
return 0;
|
return spl::BootReason_Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,37 +60,38 @@ namespace ams::boot {
|
||||||
/* Get values from PMIC. */
|
/* Get values from PMIC. */
|
||||||
{
|
{
|
||||||
PmicDriver pmic_driver;
|
PmicDriver pmic_driver;
|
||||||
R_ABORT_UNLESS(pmic_driver.GetPowerIntr(&power_intr));
|
R_ABORT_UNLESS(pmic_driver.GetOnOffIrq(std::addressof(power_intr)));
|
||||||
R_ABORT_UNLESS(pmic_driver.GetNvErc(&nv_erc));
|
R_ABORT_UNLESS(pmic_driver.GetNvErc(std::addressof(nv_erc)));
|
||||||
R_ABORT_UNLESS(pmic_driver.GetAcOk(&ac_ok));
|
R_ABORT_UNLESS(pmic_driver.GetAcOk(std::addressof(ac_ok)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get values from RTC. */
|
/* Get values from RTC. */
|
||||||
{
|
{
|
||||||
RtcDriver rtc_driver;
|
RtcDriver rtc_driver;
|
||||||
R_ABORT_UNLESS(rtc_driver.GetRtcIntr(&rtc_intr));
|
R_ABORT_UNLESS(rtc_driver.GetRtcIntr(std::addressof(rtc_intr)));
|
||||||
R_ABORT_UNLESS(rtc_driver.GetRtcIntrM(&rtc_intr_m));
|
R_ABORT_UNLESS(rtc_driver.GetRtcIntrM(std::addressof(rtc_intr_m)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set global derived boot reason. */
|
/* Set global derived boot reason. */
|
||||||
g_boot_reason = MakeBootReason(power_intr, rtc_intr & ~rtc_intr_m, nv_erc, ac_ok);
|
g_boot_reason = DetectBootReason(power_intr, rtc_intr & ~rtc_intr_m, nv_erc, ac_ok);
|
||||||
|
|
||||||
/* Set boot reason for SPL. */
|
/* Set boot reason for SPL. */
|
||||||
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||||
|
/* Create the boot reason value. */
|
||||||
spl::BootReasonValue boot_reason_value = {};
|
spl::BootReasonValue boot_reason_value = {};
|
||||||
|
|
||||||
boot_reason_value.power_intr = power_intr;
|
boot_reason_value.power_intr = power_intr;
|
||||||
boot_reason_value.rtc_intr = rtc_intr & ~rtc_intr_m;
|
boot_reason_value.rtc_intr = rtc_intr & ~rtc_intr_m;
|
||||||
boot_reason_value.nv_erc = nv_erc;
|
boot_reason_value.nv_erc = nv_erc;
|
||||||
boot_reason_value.boot_reason = g_boot_reason;
|
boot_reason_value.boot_reason = g_boot_reason;
|
||||||
|
|
||||||
|
/* Set the boot reason value. */
|
||||||
R_ABORT_UNLESS(spl::SetBootReason(boot_reason_value));
|
R_ABORT_UNLESS(spl::SetBootReason(boot_reason_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
g_detected_boot_reason = true;
|
g_detected_boot_reason = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetBootReason() {
|
spl::BootReason GetBootReason() {
|
||||||
AMS_ABORT_UNLESS(g_detected_boot_reason);
|
AMS_ABORT_UNLESS(g_detected_boot_reason);
|
||||||
return g_boot_reason;
|
return g_boot_reason;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,6 @@ namespace ams::boot {
|
||||||
|
|
||||||
/* Boot Reason utilities. */
|
/* Boot Reason utilities. */
|
||||||
void DetectBootReason();
|
void DetectBootReason();
|
||||||
u32 GetBootReason();
|
spl::BootReason GetBootReason();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
namespace ams::boot::bq24193 {
|
|
||||||
|
|
||||||
constexpr u8 InputSourceControl = 0x00;
|
|
||||||
constexpr u8 PowerOnConfiguration = 0x01;
|
|
||||||
constexpr u8 ChargeCurrentControl = 0x02;
|
|
||||||
constexpr u8 PreChargeTerminationCurrentControl = 0x03;
|
|
||||||
constexpr u8 ChargeVoltageControl = 0x04;
|
|
||||||
constexpr u8 ChargeTerminationTimerControl = 0x05;
|
|
||||||
constexpr u8 IrCompensationThermalRegulationControl = 0x06;
|
|
||||||
constexpr u8 MiscOperationControl = 0x07;
|
|
||||||
constexpr u8 SystemStatus = 0x08;
|
|
||||||
constexpr u8 Fault = 0x09;
|
|
||||||
constexpr u8 VendorPartRevisionStatus = 0x0A;
|
|
||||||
|
|
||||||
enum ChargerConfiguration : u8 {
|
|
||||||
ChargerConfiguration_ChargeDisable = (0 << 4),
|
|
||||||
ChargerConfiguration_ChargeBattery = (1 << 4),
|
|
||||||
ChargerConfiguration_Otg = (2 << 4),
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr u32 ChargeVoltageLimitMin = 3504;
|
|
||||||
constexpr u32 ChargeVoltageLimitMax = 4208;
|
|
||||||
|
|
||||||
inline u8 EncodeChargeVoltageLimit(u32 voltage) {
|
|
||||||
AMS_ABORT_UNLESS(voltage >= ChargeVoltageLimitMin);
|
|
||||||
AMS_ABORT_UNLESS(voltage <= ChargeVoltageLimitMax);
|
|
||||||
|
|
||||||
voltage -= ChargeVoltageLimitMin;
|
|
||||||
voltage >>= 4;
|
|
||||||
return static_cast<u8>(voltage << 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 DecodeChargeVoltageLimit(u8 reg) {
|
|
||||||
return ChargeVoltageLimitMin + (static_cast<u32>(reg & 0xFC) << 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 FastChargeCurrentLimitMin = 512;
|
|
||||||
constexpr u32 FastChargeCurrentLimitMax = 4544;
|
|
||||||
|
|
||||||
inline u8 EncodeFastChargeCurrentLimit(u32 current) {
|
|
||||||
AMS_ABORT_UNLESS(current >= FastChargeCurrentLimitMin);
|
|
||||||
AMS_ABORT_UNLESS(current <= FastChargeCurrentLimitMax);
|
|
||||||
|
|
||||||
current -= FastChargeCurrentLimitMin;
|
|
||||||
current >>= 6;
|
|
||||||
return static_cast<u8>(current << 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 DecodeFastChargeCurrentLimit(u8 reg) {
|
|
||||||
return FastChargeCurrentLimitMin + (static_cast<u32>(reg & 0xFC) << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum InputCurrentLimit : u8 {
|
|
||||||
InputCurrentLimit_100mA = 0,
|
|
||||||
InputCurrentLimit_150mA = 1,
|
|
||||||
InputCurrentLimit_500mA = 2,
|
|
||||||
InputCurrentLimit_900mA = 3,
|
|
||||||
InputCurrentLimit_1200mA = 4,
|
|
||||||
InputCurrentLimit_1500mA = 5,
|
|
||||||
InputCurrentLimit_2000mA = 6,
|
|
||||||
InputCurrentLimit_3000mA = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr u32 PreChargeCurrentLimitMin = 128;
|
|
||||||
constexpr u32 PreChargeCurrentLimitMax = 2048;
|
|
||||||
|
|
||||||
inline u8 EncodePreChargeCurrentLimit(u32 current) {
|
|
||||||
AMS_ABORT_UNLESS(current >= PreChargeCurrentLimitMin);
|
|
||||||
AMS_ABORT_UNLESS(current <= PreChargeCurrentLimitMax);
|
|
||||||
|
|
||||||
current -= PreChargeCurrentLimitMin;
|
|
||||||
current >>= 7;
|
|
||||||
return static_cast<u8>(current << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 DecodePreChargeCurrentLimit(u8 reg) {
|
|
||||||
return PreChargeCurrentLimitMin + (static_cast<u32>(reg & 0xF0) << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 TerminationCurrentLimitMin = 128;
|
|
||||||
constexpr u32 TerminationCurrentLimitMax = 2048;
|
|
||||||
|
|
||||||
inline u8 EncodeTerminationCurrentLimit(u32 current) {
|
|
||||||
AMS_ABORT_UNLESS(current >= TerminationCurrentLimitMin);
|
|
||||||
AMS_ABORT_UNLESS(current <= TerminationCurrentLimitMax);
|
|
||||||
|
|
||||||
current -= TerminationCurrentLimitMin;
|
|
||||||
current >>= 7;
|
|
||||||
return static_cast<u8>(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 DecodeTerminationCurrentLimit(u8 reg) {
|
|
||||||
return TerminationCurrentLimitMin + (static_cast<u32>(reg & 0xF) << 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr u32 MinimumSystemVoltageLimitMin = 3000;
|
|
||||||
constexpr u32 MinimumSystemVoltageLimitMax = 3700;
|
|
||||||
|
|
||||||
inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) {
|
|
||||||
AMS_ABORT_UNLESS(voltage >= MinimumSystemVoltageLimitMin);
|
|
||||||
AMS_ABORT_UNLESS(voltage <= MinimumSystemVoltageLimitMax);
|
|
||||||
|
|
||||||
voltage -= MinimumSystemVoltageLimitMin;
|
|
||||||
voltage /= 100;
|
|
||||||
return static_cast<u8>(voltage << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 DecodeMinimumSystemVoltageLimit(u8 reg) {
|
|
||||||
return MinimumSystemVoltageLimitMin + (static_cast<u32>(reg & 0x0E) * 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum WatchdogTimerSetting : u8 {
|
|
||||||
WatchdogTimerSetting_Disabled = (0 << 4),
|
|
||||||
WatchdogTimerSetting_40s = (1 << 4),
|
|
||||||
WatchdogTimerSetting_80s = (2 << 4),
|
|
||||||
WatchdogTimerSetting_160s = (3 << 4),
|
|
||||||
};
|
|
||||||
|
|
||||||
enum BoostModeCurrentLimit : u8 {
|
|
||||||
BoostModeCurrentLimit_500mA = 0,
|
|
||||||
BoostModeCurrentLimit_1300mA = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#include "boot_calibration.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/* Convenience definitions. */
|
|
||||||
constexpr size_t BatteryLotOffset = 0x2CE0;
|
|
||||||
constexpr size_t BatteryLotSize = 0x20;
|
|
||||||
constexpr size_t BatteryVersionOffset = 0x4310;
|
|
||||||
constexpr size_t BatteryVersionSize = 0x10;
|
|
||||||
|
|
||||||
constexpr u32 DefaultBatteryVendor = static_cast<u32>('A');
|
|
||||||
constexpr u32 DefaultBatteryVersion = 0;
|
|
||||||
|
|
||||||
/* Helpers. */
|
|
||||||
constexpr u16 GetCrc16(const void *data, size_t size) {
|
|
||||||
constexpr u16 s_crc_table[0x10] = {
|
|
||||||
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
|
|
||||||
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
|
||||||
};
|
|
||||||
|
|
||||||
AMS_ABORT_UNLESS(data != nullptr);
|
|
||||||
|
|
||||||
u16 crc16 = 0x55AA;
|
|
||||||
const u8 *data_u8 = reinterpret_cast<const u8 *>(data);
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
crc16 = (crc16 >> 4) ^ (s_crc_table[crc16 & 0xF]) ^ (s_crc_table[data_u8[i] & 0xF]);
|
|
||||||
crc16 = (crc16 >> 4) ^ (s_crc_table[crc16 & 0xF]) ^ (s_crc_table[(data_u8[i] >> 4) & 0xF]);
|
|
||||||
}
|
|
||||||
return crc16;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ValidateCalibrationCrc16(const void *data, size_t size) {
|
|
||||||
const u8 *data_u8 = reinterpret_cast<const u8 *>(data);
|
|
||||||
const bool crc_valid = GetCrc16(data, size - sizeof(u16)) == *(reinterpret_cast<const u16 *>(&data_u8[size - sizeof(u16)]));
|
|
||||||
R_UNLESS(crc_valid, cal::ResultCalibrationDataCrcError());
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result GetBatteryVendorImpl(u32 *vendor) {
|
|
||||||
FsStorage s;
|
|
||||||
R_TRY(fsOpenBisStorage(&s, FsBisPartitionId_CalibrationBinary));
|
|
||||||
ON_SCOPE_EXIT { fsStorageClose(&s); };
|
|
||||||
|
|
||||||
u8 battery_lot[BatteryLotSize];
|
|
||||||
R_TRY(fsStorageRead(&s, BatteryLotOffset, battery_lot, sizeof(battery_lot)));
|
|
||||||
|
|
||||||
R_TRY(ValidateCalibrationCrc16(battery_lot, sizeof(battery_lot)));
|
|
||||||
|
|
||||||
*vendor = battery_lot[7];
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result GetBatteryVersionImpl(u32 *version) {
|
|
||||||
FsStorage s;
|
|
||||||
R_TRY(fsOpenBisStorage(&s, FsBisPartitionId_CalibrationBinary));
|
|
||||||
ON_SCOPE_EXIT { fsStorageClose(&s); };
|
|
||||||
|
|
||||||
u8 battery_version[BatteryVersionSize];
|
|
||||||
R_TRY(fsStorageRead(&s, BatteryVersionOffset, battery_version, sizeof(battery_version)));
|
|
||||||
|
|
||||||
R_TRY(ValidateCalibrationCrc16(battery_version, sizeof(battery_version)));
|
|
||||||
|
|
||||||
*version = battery_version[0];
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetBatteryVendor() {
|
|
||||||
u32 vendor;
|
|
||||||
if (R_FAILED(GetBatteryVendorImpl(&vendor))) {
|
|
||||||
return DefaultBatteryVendor;
|
|
||||||
}
|
|
||||||
return vendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetBatteryVersion() {
|
|
||||||
u32 version;
|
|
||||||
if (R_FAILED(GetBatteryVersionImpl(&version))) {
|
|
||||||
return DefaultBatteryVersion;
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "boot_change_voltage.hpp"
|
#include "boot_change_voltage.hpp"
|
||||||
#include "boot_pmc_wrapper.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
|
@ -36,8 +35,8 @@ namespace ams::boot {
|
||||||
|
|
||||||
void ChangeGpioVoltageTo1_8v() {
|
void ChangeGpioVoltageTo1_8v() {
|
||||||
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
||||||
WritePmcRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask);
|
dd::ReadModifyWriteIoRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask);
|
||||||
WritePmcRegister(PmcPwrDetVal, 0, VoltageChangeMask);
|
dd::ReadModifyWriteIoRegister(PmcPwrDetVal, 0, VoltageChangeMask);
|
||||||
|
|
||||||
/* Sleep for 100 us. */
|
/* Sleep for 100 us. */
|
||||||
svcSleepThread(100'000ul);
|
svcSleepThread(100'000ul);
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#include "boot_charger_driver.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
|
||||||
|
|
||||||
Result ChargerDriver::Read(u8 addr, u8 *out) {
|
|
||||||
return ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::Write(u8 addr, u8 val) {
|
|
||||||
return WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::ReadWrite(u8 addr, u8 mask, u8 val) {
|
|
||||||
u8 cur_val;
|
|
||||||
R_TRY(this->Read(addr, &cur_val));
|
|
||||||
|
|
||||||
const u8 new_val = (cur_val & ~mask) | val;
|
|
||||||
R_TRY(this->Write(addr, new_val));
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::Initialize() {
|
|
||||||
return this->Initialize(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::Initialize(bool set_input_current_limit) {
|
|
||||||
if (set_input_current_limit) {
|
|
||||||
R_TRY(this->SetInputCurrentLimit(bq24193::InputCurrentLimit_500mA));
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(this->SetChargeVoltageLimit(4208));
|
|
||||||
R_TRY(this->SetFastChargeCurrentLimit(512));
|
|
||||||
R_TRY(this->SetForce20PercentChargeCurrent(false));
|
|
||||||
R_TRY(this->SetPreChargeCurrentLimit(128));
|
|
||||||
R_TRY(this->SetTerminationCurrentLimit(128));
|
|
||||||
R_TRY(this->SetMinimumSystemVoltageLimit(3000));
|
|
||||||
R_TRY(this->SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting_Disabled));
|
|
||||||
R_TRY(this->SetChargingSafetyTimerEnabled(false));
|
|
||||||
R_TRY(this->ResetWatchdogTimer());
|
|
||||||
R_TRY(this->SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit_500mA));
|
|
||||||
R_TRY(this->SetHiZEnabled(false));
|
|
||||||
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetChargeEnabled(bool enabled) {
|
|
||||||
/* TODO */
|
|
||||||
AMS_ABORT();
|
|
||||||
/* boot::gpio::SetValue(GpioPadName_Bq24193Charger, enabled ? GpioValue_Low : GpioValue_High); */
|
|
||||||
return this->SetChargerConfiguration(bq24193::ChargerConfiguration_ChargeBattery);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetChargerConfiguration(bq24193::ChargerConfiguration config) {
|
|
||||||
return this->ReadWrite(bq24193::PowerOnConfiguration, 0x30, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetChargeVoltageLimit(u32 voltage) {
|
|
||||||
return this->ReadWrite(bq24193::ChargeVoltageControl, 0xFC, bq24193::EncodeChargeVoltageLimit(voltage));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetFastChargeCurrentLimit(u32 current) {
|
|
||||||
return this->ReadWrite(bq24193::ChargeCurrentControl, 0xFC, bq24193::EncodeFastChargeCurrentLimit(current));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetInputCurrentLimit(bq24193::InputCurrentLimit current) {
|
|
||||||
return this->ReadWrite(bq24193::InputSourceControl, 0x07, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetForce20PercentChargeCurrent(bool force) {
|
|
||||||
return this->ReadWrite(bq24193::ChargeCurrentControl, 0x01, force ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetPreChargeCurrentLimit(u32 current) {
|
|
||||||
return this->ReadWrite(bq24193::PreChargeTerminationCurrentControl, 0xF0, bq24193::EncodePreChargeCurrentLimit(current));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetTerminationCurrentLimit(u32 current) {
|
|
||||||
return this->ReadWrite(bq24193::PreChargeTerminationCurrentControl, 0x0F, bq24193::EncodeTerminationCurrentLimit(current));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetMinimumSystemVoltageLimit(u32 voltage) {
|
|
||||||
return this->ReadWrite(bq24193::PowerOnConfiguration, 0x0E, bq24193::EncodeMinimumSystemVoltageLimit(voltage));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting setting) {
|
|
||||||
return this->ReadWrite(bq24193::ChargeTerminationTimerControl, 0x30, setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetChargingSafetyTimerEnabled(bool enabled) {
|
|
||||||
return this->ReadWrite(bq24193::ChargeTerminationTimerControl, 0x08, enabled ? 0x08 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::ResetWatchdogTimer() {
|
|
||||||
return this->ReadWrite(bq24193::PowerOnConfiguration, 0x40, 0x40);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit current) {
|
|
||||||
return this->ReadWrite(bq24193::PowerOnConfiguration, 0x01, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::SetHiZEnabled(bool enabled) {
|
|
||||||
return this->ReadWrite(bq24193::InputSourceControl, 0x80, enabled ? 0x80 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::GetInputCurrentLimit(bq24193::InputCurrentLimit *out) {
|
|
||||||
u8 limit;
|
|
||||||
R_TRY(this->Read(bq24193::InputSourceControl, &limit));
|
|
||||||
*out = static_cast<bq24193::InputCurrentLimit>(limit);
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ChargerDriver::GetChargeVoltageLimit(u32 *out) {
|
|
||||||
u8 reg;
|
|
||||||
R_TRY(this->Read(bq24193::ChargeVoltageControl, ®));
|
|
||||||
*out = bq24193::DecodeChargeVoltageLimit(reg);
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -14,52 +14,111 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "boot_bq24193_charger.hpp"
|
#include <stratosphere.hpp>
|
||||||
#include "boot_i2c_utils.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
|
enum ChargerStatus {
|
||||||
|
ChargerStatus_Unknown = 0,
|
||||||
|
ChargerStatus_Charging = 1,
|
||||||
|
ChargerStatus_NotCharging = 2,
|
||||||
|
ChargerStatus_ChargeTerminationDone = 3,
|
||||||
|
};
|
||||||
|
|
||||||
class ChargerDriver {
|
class ChargerDriver {
|
||||||
private:
|
private:
|
||||||
static constexpr u32 GpioPadName_Bq24193Charger = 0xA;
|
powctl::Session charger_session;
|
||||||
private:
|
|
||||||
i2c::driver::I2cSession i2c_session;
|
|
||||||
public:
|
public:
|
||||||
ChargerDriver() {
|
ChargerDriver() : charger_session() {
|
||||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Bq24193));
|
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(this->charger_session), powctl::DeviceCode_Bq24193, ddsf::AccessMode_ReadWrite));
|
||||||
|
|
||||||
//boot::gpio::Configure(GpioPadName_Bq24193Charger);
|
|
||||||
//boot::gpio::SetDirection(GpioPadName_Bq24193Charger, GpioDirection_Output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ChargerDriver() {
|
~ChargerDriver() {
|
||||||
i2c::driver::CloseSession(this->i2c_session);
|
powctl::CloseSession(this->charger_session);
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
Result Read(u8 addr, u8 *out_data);
|
|
||||||
Result Write(u8 addr, u8 val);
|
|
||||||
Result ReadWrite(u8 addr, u8 mask, u8 val);
|
|
||||||
|
|
||||||
Result SetInputCurrentLimit(bq24193::InputCurrentLimit current);
|
Result Initialize(bool set_input_current_limit) {
|
||||||
Result SetForce20PercentChargeCurrent(bool force);
|
/* Set input current limit to 500 ma. */
|
||||||
Result SetPreChargeCurrentLimit(u32 current);
|
if (set_input_current_limit) {
|
||||||
Result SetTerminationCurrentLimit(u32 current);
|
R_TRY(powctl::SetChargerInputCurrentLimit(this->charger_session, 500));
|
||||||
Result SetMinimumSystemVoltageLimit(u32 voltage);
|
}
|
||||||
Result SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting setting);
|
|
||||||
Result SetChargingSafetyTimerEnabled(bool enabled);
|
|
||||||
Result ResetWatchdogTimer();
|
|
||||||
Result SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit current);
|
|
||||||
Result SetHiZEnabled(bool enabled);
|
|
||||||
|
|
||||||
public:
|
/* Set input voltage limit to 500 mv. */
|
||||||
Result Initialize();
|
R_TRY(powctl::SetChargerInputVoltageLimit(this->charger_session, 500));
|
||||||
Result Initialize(bool set_input_current_limit);
|
|
||||||
Result SetChargeVoltageLimit(u32 voltage);
|
/* Disable hi-z mode. */
|
||||||
Result SetFastChargeCurrentLimit(u32 current);
|
R_TRY(powctl::SetChargerHiZEnabled(this->charger_session, false));
|
||||||
Result SetChargeEnabled(bool enabled);
|
|
||||||
Result SetChargerConfiguration(bq24193::ChargerConfiguration config);
|
/* Set configuration to charge battery. */
|
||||||
Result GetInputCurrentLimit(bq24193::InputCurrentLimit *out);
|
R_TRY(powctl::SetChargerChargerConfiguration(this->charger_session, powctl::ChargerConfiguration_ChargeBattery));
|
||||||
Result GetChargeVoltageLimit(u32 *out);
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetChargeCurrentState(powctl::ChargeCurrentState *out) {
|
||||||
|
return powctl::GetChargerChargeCurrentState(out, this->charger_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetChargeCurrentState(powctl::ChargeCurrentState state) {
|
||||||
|
return powctl::SetChargerChargeCurrentState(this->charger_session, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetInputCurrentLimit(int *out) {
|
||||||
|
return powctl::GetChargerInputCurrentLimit(out, this->charger_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetChargerConfiguration(powctl::ChargerConfiguration cfg) {
|
||||||
|
return powctl::SetChargerChargerConfiguration(this->charger_session, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetFastChargeCurrentLimit(int *out) {
|
||||||
|
return powctl::GetChargerFastChargeCurrentLimit(out, this->charger_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetFastChargeCurrentLimit(int limit) {
|
||||||
|
return powctl::SetChargerFastChargeCurrentLimit(this->charger_session, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetChargeVoltageLimit(int *out) {
|
||||||
|
return powctl::GetChargerChargeVoltageLimit(out, this->charger_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetChargeVoltageLimit(int limit) {
|
||||||
|
return powctl::SetChargerChargeVoltageLimit(this->charger_session, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetChargerStatus(boot::ChargerStatus *out) {
|
||||||
|
/* Default to unknown. */
|
||||||
|
*out = ChargerStatus_Unknown;
|
||||||
|
|
||||||
|
/* Get the powctl status. */
|
||||||
|
powctl::ChargerStatus powctl_status;
|
||||||
|
R_TRY(powctl::GetChargerChargerStatus(std::addressof(powctl_status), this->charger_session));
|
||||||
|
|
||||||
|
switch (powctl_status) {
|
||||||
|
case powctl::ChargerStatus_Charging: *out = boot::ChargerStatus_Charging; break;
|
||||||
|
case powctl::ChargerStatus_NotCharging: *out = boot::ChargerStatus_NotCharging; break;
|
||||||
|
case powctl::ChargerStatus_ChargeTerminationDone: *out = boot::ChargerStatus_ChargeTerminationDone; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetBatteryCompensation(int *out) {
|
||||||
|
return powctl::GetChargerBatteryCompensation(out, this->charger_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetBatteryCompensation(int v) {
|
||||||
|
return powctl::SetChargerBatteryCompensation(this->charger_session, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetVoltageClamp(int *out) {
|
||||||
|
return powctl::GetChargerVoltageClamp(out, this->charger_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetVoltageClamp(int v) {
|
||||||
|
return powctl::SetChargerVoltageClamp(this->charger_session, v);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,19 +14,25 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "boot_battery_driver.hpp"
|
#include "boot_check_battery.hpp"
|
||||||
#include "boot_battery_icons.hpp"
|
#include "boot_battery_icons.hpp"
|
||||||
#include "boot_boot_reason.hpp"
|
#include "boot_boot_reason.hpp"
|
||||||
#include "boot_calibration.hpp"
|
|
||||||
#include "boot_charger_driver.hpp"
|
|
||||||
#include "boot_check_battery.hpp"
|
|
||||||
#include "boot_pmic_driver.hpp"
|
#include "boot_pmic_driver.hpp"
|
||||||
|
#include "boot_battery_driver.hpp"
|
||||||
|
#include "boot_charger_driver.hpp"
|
||||||
#include "boot_power_utils.hpp"
|
#include "boot_power_utils.hpp"
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
/* Value definitions. */
|
||||||
|
constexpr inline double BatteryLevelThresholdForBoot = 3.0;
|
||||||
|
constexpr inline double BatteryLevelThresholdForFullCharge = 99.0;
|
||||||
|
|
||||||
|
constexpr inline int BatteryVoltageThresholdConnected = 4000;
|
||||||
|
constexpr inline int BatteryVoltageThresholdDisconnected = 3650;
|
||||||
|
|
||||||
/* Types. */
|
/* Types. */
|
||||||
enum class CheckBatteryResult {
|
enum class CheckBatteryResult {
|
||||||
Success,
|
Success,
|
||||||
|
@ -34,251 +40,488 @@ namespace ams::boot {
|
||||||
Reboot,
|
Reboot,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BatteryChargeParameters {
|
class BatteryChecker {
|
||||||
u32 temp_min;
|
private:
|
||||||
u32 temp_low;
|
boot::ChargerDriver &charger_driver;
|
||||||
u32 temp_high;
|
boot::BatteryDriver &battery_driver;
|
||||||
u32 temp_max;
|
const powctl::driver::impl::ChargeParameters &charge_parameters;
|
||||||
u32 allow_high_temp_charge_max_voltage;
|
powctl::driver::impl::ChargeArbiter charge_arbiter;
|
||||||
u32 charge_voltage_limit_default;
|
powctl::ChargeCurrentState charge_current_state;
|
||||||
u32 charge_voltage_limit_high_temp;
|
int fast_charge_current_limit;
|
||||||
u32 allow_fast_charge_min_temp;
|
int charge_voltage_limit;
|
||||||
u32 allow_fast_charge_min_voltage;
|
int battery_compensation;
|
||||||
u32 fast_charge_current_limit_default;
|
int voltage_clamp;
|
||||||
u32 fast_charge_current_limit_low_temp;
|
TimeSpan charging_done_interval;
|
||||||
u32 fast_charge_current_limit_low_voltage;
|
bool has_start_time;
|
||||||
|
TimeSpan start_time;
|
||||||
|
private:
|
||||||
|
bool IsChargeDone();
|
||||||
|
void UpdateChargeDoneCurrent();
|
||||||
|
void ApplyArbiterRule();
|
||||||
|
void PrintBatteryStatus(float raw_charge, int voltage, int voltage_threshold);
|
||||||
|
CheckBatteryResult LoopCheckBattery(bool reboot_on_power_button_press, bool return_on_enough_battery, bool shutdown_on_full_battery, bool show_display, bool show_charging_display);
|
||||||
|
|
||||||
|
void UpdateStartTime() {
|
||||||
|
/* Update start time. */
|
||||||
|
this->start_time = os::ConvertToTimeSpan(os::GetSystemTick());
|
||||||
|
this->has_start_time = true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
BatteryChecker(boot::ChargerDriver &cd, boot::BatteryDriver &bd, const powctl::driver::impl::ChargeParameters &cp, int cvl) : charger_driver(cd), battery_driver(bd), charge_parameters(cp), charge_arbiter(cp.rules, cp.num_rules, cvl), charging_done_interval(TimeSpan::FromSeconds(2)), has_start_time(false) {
|
||||||
|
/* Get parameters from charger. */
|
||||||
|
if (R_FAILED(this->charger_driver.GetChargeCurrentState(std::addressof(this->charge_current_state)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->charger_driver.GetFastChargeCurrentLimit(std::addressof(this->fast_charge_current_limit)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->charger_driver.GetChargeVoltageLimit(std::addressof(this->charge_voltage_limit)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->charger_driver.GetBatteryCompensation(std::addressof(this->battery_compensation)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->charger_driver.GetVoltageClamp(std::addressof(this->voltage_clamp)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBatteryResult LoopCheckBattery(spl::BootReason boot_reason) {
|
||||||
|
if (boot_reason == spl::BootReason_RtcAlarm2) {
|
||||||
|
/* RTC Alarm 2 boot (QuasiOff) */
|
||||||
|
return this->LoopCheckBattery(true, false, true, false, false);
|
||||||
|
} else if (boot_reason == spl::BootReason_AcOk) {
|
||||||
|
/* ACOK boot */
|
||||||
|
return this->LoopCheckBattery(true, true, false, true, true);
|
||||||
|
} else {
|
||||||
|
/* Normal boot */
|
||||||
|
return this->LoopCheckBattery(false, true, false, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateCharger();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Battery parameters. */
|
void BatteryChecker::PrintBatteryStatus(float raw_charge, int voltage, int voltage_threshold) {
|
||||||
constexpr BatteryChargeParameters BatteryChargeParameters0 = {
|
/* TODO: Print charge/voltage/threshold. */
|
||||||
.temp_min = 4,
|
AMS_UNUSED(raw_charge, voltage, voltage_threshold);
|
||||||
.temp_low = 17,
|
|
||||||
.temp_high = 51,
|
|
||||||
.temp_max = 60,
|
|
||||||
.allow_high_temp_charge_max_voltage = 4050,
|
|
||||||
.charge_voltage_limit_default = 4208,
|
|
||||||
.charge_voltage_limit_high_temp = 3952,
|
|
||||||
.allow_fast_charge_min_voltage = 3320,
|
|
||||||
.fast_charge_current_limit_default = 0x800,
|
|
||||||
.fast_charge_current_limit_low_temp = 0x300,
|
|
||||||
.fast_charge_current_limit_low_voltage = 0x200,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr BatteryChargeParameters BatteryChargeParameters1 = {
|
/* Get various battery metrics. */
|
||||||
.temp_min = 4,
|
int avg_current, current, open_circuit_voltage;
|
||||||
.temp_low = 17,
|
float temp;
|
||||||
.temp_high = 51,
|
if (R_FAILED(this->battery_driver.GetAverageCurrent(std::addressof(avg_current)))) {
|
||||||
.temp_max = 59,
|
return;
|
||||||
.allow_high_temp_charge_max_voltage = 3984,
|
|
||||||
.charge_voltage_limit_default = 4208,
|
|
||||||
.charge_voltage_limit_high_temp = 3984,
|
|
||||||
.allow_fast_charge_min_voltage = 0,
|
|
||||||
.fast_charge_current_limit_default = 0x600,
|
|
||||||
.fast_charge_current_limit_low_temp = 0x240,
|
|
||||||
.fast_charge_current_limit_low_voltage = 0x600,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr BatteryChargeParameters BatteryChargeParameters2 = {
|
|
||||||
.temp_min = 4,
|
|
||||||
.temp_low = 17,
|
|
||||||
.temp_high = 51,
|
|
||||||
.temp_max = 59,
|
|
||||||
.allow_high_temp_charge_max_voltage = 4080,
|
|
||||||
.charge_voltage_limit_default = 4320,
|
|
||||||
.charge_voltage_limit_high_temp = 4080,
|
|
||||||
.allow_fast_charge_min_voltage = 0,
|
|
||||||
.fast_charge_current_limit_default = 0x680,
|
|
||||||
.fast_charge_current_limit_low_temp = 0x280,
|
|
||||||
.fast_charge_current_limit_low_voltage = 0x680,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr const BatteryChargeParameters *GetBatteryChargeParameters(u32 battery_version) {
|
|
||||||
switch (battery_version) {
|
|
||||||
case 0:
|
|
||||||
return &BatteryChargeParameters0;
|
|
||||||
case 1:
|
|
||||||
return &BatteryChargeParameters1;
|
|
||||||
case 2:
|
|
||||||
return &BatteryChargeParameters2;
|
|
||||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
|
||||||
}
|
}
|
||||||
|
if (R_FAILED(this->battery_driver.GetCurrent(std::addressof(current)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (R_FAILED(this->battery_driver.GetOpenCircuitVoltage(std::addressof(open_circuit_voltage)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Print the things we just got. */
|
||||||
|
AMS_UNUSED(avg_current, current, temp, open_circuit_voltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helpers. */
|
bool BatteryChecker::IsChargeDone() {
|
||||||
void UpdateCharger(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit) {
|
/* Get the charger status. */
|
||||||
double temperature;
|
boot::ChargerStatus charger_status;
|
||||||
u32 battery_voltage;
|
if (R_FAILED(this->charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
if (R_FAILED(battery_driver->GetTemperature(&temperature)) || R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) {
|
|
||||||
pmic_driver->ShutdownSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool enable_charge = true;
|
/* If charge status isn't done, we're not done. */
|
||||||
if (temperature < double(params->temp_min)) {
|
if (charger_status != boot::ChargerStatus_ChargeTerminationDone) {
|
||||||
enable_charge = false;
|
return false;
|
||||||
} else if (double(params->temp_high) <= temperature && temperature < double(params->temp_max)) {
|
}
|
||||||
if (battery_voltage < params->allow_high_temp_charge_max_voltage) {
|
|
||||||
charge_voltage_limit = std::min(charge_voltage_limit, params->charge_voltage_limit_high_temp);
|
/* Return whether a done current of zero is acceptable. */
|
||||||
} else {
|
return this->charge_arbiter.IsBatteryDoneCurrentAcceptable(0);
|
||||||
enable_charge = false;
|
}
|
||||||
|
|
||||||
|
void BatteryChecker::UpdateChargeDoneCurrent() {
|
||||||
|
int done_current = 0;
|
||||||
|
if (this->has_start_time && (os::ConvertToTimeSpan(os::GetSystemTick()) - this->start_time) >= this->charging_done_interval) {
|
||||||
|
/* Get the current. */
|
||||||
|
if (R_FAILED(this->battery_driver.GetCurrent(std::addressof(done_current)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
}
|
}
|
||||||
} else if (double(params->temp_max) <= temperature) {
|
} else {
|
||||||
enable_charge = false;
|
/* Get the charger status. */
|
||||||
if (battery_voltage < params->allow_high_temp_charge_max_voltage) {
|
boot::ChargerStatus charger_status;
|
||||||
charge_voltage_limit = std::min(charge_voltage_limit, params->charge_voltage_limit_high_temp);
|
if (R_FAILED(this->charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the charger status isn't done, don't update. */
|
||||||
|
if (charger_status != boot::ChargerStatus_ChargeTerminationDone) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fast_charge_current_limit = params->fast_charge_current_limit_default;
|
/* Update done current. */
|
||||||
if (temperature < double(params->temp_low)) {
|
this->charge_arbiter.SetBatteryDoneCurrent(done_current);
|
||||||
fast_charge_current_limit = std::min(fast_charge_current_limit, params->fast_charge_current_limit_low_temp);
|
}
|
||||||
}
|
|
||||||
if (battery_voltage < params->allow_fast_charge_min_voltage) {
|
void BatteryChecker::UpdateCharger() {
|
||||||
fast_charge_current_limit = std::min(fast_charge_current_limit, params->fast_charge_current_limit_low_voltage);
|
/* Get the battery temperature. */
|
||||||
|
float temp;
|
||||||
|
if (R_FAILED(this->battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(charger_driver->SetChargeEnabled(enable_charge))) {
|
/* Update the temperature level. */
|
||||||
pmic_driver->ShutdownSystem();
|
powctl::BatteryTemperatureLevel temp_level;
|
||||||
|
if (temp < static_cast<float>(this->charge_parameters.temp_min)) {
|
||||||
|
temp_level = powctl::BatteryTemperatureLevel::TooLow;
|
||||||
|
} else if (temp < static_cast<float>(this->charge_parameters.temp_low)) {
|
||||||
|
temp_level = powctl::BatteryTemperatureLevel::Low;
|
||||||
|
} else if (temp < static_cast<float>(this->charge_parameters.temp_high)) {
|
||||||
|
temp_level = powctl::BatteryTemperatureLevel::Medium;
|
||||||
|
} else if (temp < static_cast<float>(this->charge_parameters.temp_max)) {
|
||||||
|
temp_level = powctl::BatteryTemperatureLevel::High;
|
||||||
|
} else {
|
||||||
|
temp_level = powctl::BatteryTemperatureLevel::TooHigh;
|
||||||
}
|
}
|
||||||
if (R_FAILED(charger_driver->SetChargeVoltageLimit(charge_voltage_limit))) {
|
this->charge_arbiter.SetBatteryTemperatureLevel(temp_level);
|
||||||
pmic_driver->ShutdownSystem();
|
|
||||||
|
/* Update average voltage. */
|
||||||
|
int avg_v_cell;
|
||||||
|
if (R_FAILED(this->battery_driver.GetAverageVCell(std::addressof(avg_v_cell)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
}
|
}
|
||||||
if (R_FAILED(charger_driver->SetFastChargeCurrentLimit(fast_charge_current_limit))) {
|
this->charge_arbiter.SetBatteryAverageVCell(avg_v_cell);
|
||||||
pmic_driver->ShutdownSystem();
|
|
||||||
|
/* Update open circuit voltage. */
|
||||||
|
int ocv;
|
||||||
|
if (R_FAILED(this->battery_driver.GetOpenCircuitVoltage(std::addressof(ocv)))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->charge_arbiter.SetBatteryOpenCircuitVoltage(ocv);
|
||||||
|
|
||||||
|
/* Update charge done current. */
|
||||||
|
this->UpdateChargeDoneCurrent();
|
||||||
|
|
||||||
|
/* Update arbiter power state. */
|
||||||
|
this->charge_arbiter.SetPowerState(powctl::PowerState::ShutdownChargeMain);
|
||||||
|
|
||||||
|
/* Apply the newly selected rule. */
|
||||||
|
this->ApplyArbiterRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatteryChecker::ApplyArbiterRule() {
|
||||||
|
/* Get the selected rule. */
|
||||||
|
const auto *rule = this->charge_arbiter.GetSelectedRule();
|
||||||
|
AMS_ASSERT(rule != nullptr);
|
||||||
|
|
||||||
|
/* Check if we need to perform charger initialization. */
|
||||||
|
const bool reinit_charger = rule->reinitialize_charger;
|
||||||
|
const auto cur_charge_current_state = this->charge_current_state;
|
||||||
|
|
||||||
|
/* Set the charger to not charging while we make changes. */
|
||||||
|
if (!reinit_charger || cur_charge_current_state != powctl::ChargeCurrentState_NotCharging) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_NotCharging))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->charge_current_state = powctl::ChargeCurrentState_NotCharging;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process fast charge current limit when rule is smaller. */
|
||||||
|
const auto rule_fast_charge_current_limit = rule->fast_charge_current_limit;
|
||||||
|
const auto cur_fast_charge_current_limit = this->fast_charge_current_limit;
|
||||||
|
if (rule_fast_charge_current_limit < cur_fast_charge_current_limit) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->fast_charge_current_limit = rule_fast_charge_current_limit;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process charge voltage limit when rule is smaller. */
|
||||||
|
const auto rule_charge_voltage_limit = std::min(rule->charge_voltage_limit, this->charge_arbiter.GetChargeVoltageLimit());
|
||||||
|
const auto cur_charge_voltage_limit = this->charge_voltage_limit;
|
||||||
|
if (rule_charge_voltage_limit < cur_charge_voltage_limit) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->charge_voltage_limit = rule_charge_voltage_limit;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process battery compensation when rule is smaller. */
|
||||||
|
const auto rule_battery_compensation = rule->battery_compensation;
|
||||||
|
const auto cur_battery_compensation = this->battery_compensation;
|
||||||
|
if (rule_battery_compensation < cur_battery_compensation) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->battery_compensation = rule_battery_compensation;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process voltage clamp when rule is smaller. */
|
||||||
|
const auto rule_voltage_clamp = rule->voltage_clamp;
|
||||||
|
const auto cur_voltage_clamp = this->voltage_clamp;
|
||||||
|
if (rule_voltage_clamp < cur_voltage_clamp) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->voltage_clamp = rule_voltage_clamp;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process voltage clamp when rule is larger. */
|
||||||
|
if (rule_voltage_clamp > cur_voltage_clamp) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->voltage_clamp = rule_voltage_clamp;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process battery compensation when rule is larger. */
|
||||||
|
if (rule_battery_compensation > cur_battery_compensation) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->battery_compensation = rule_battery_compensation;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process fast charge current limit when rule is larger. */
|
||||||
|
if (rule_fast_charge_current_limit > cur_fast_charge_current_limit) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->fast_charge_current_limit = rule_fast_charge_current_limit;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process charge voltage limit when rule is larger. */
|
||||||
|
if (rule_charge_voltage_limit > cur_charge_voltage_limit) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->charge_voltage_limit = rule_charge_voltage_limit;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're not charging and we expect to reinitialize the charger, do so. */
|
||||||
|
if (cur_charge_current_state != powctl::ChargeCurrentState_Charging && reinit_charger) {
|
||||||
|
if (R_FAILED(this->charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_Charging))) {
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
this->charge_current_state = powctl::ChargeCurrentState_Charging;
|
||||||
|
|
||||||
|
/* Update start time. */
|
||||||
|
this->UpdateStartTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSufficientBattery(u32 battery_voltage, bool ac_ok) {
|
CheckBatteryResult BatteryChecker::LoopCheckBattery(bool reboot_on_power_button_press, bool return_on_enough_battery, bool shutdown_on_full_battery, bool show_display, bool show_charging_display) {
|
||||||
/* Nintendo has stuff for updating a static variable every 10 seconds here, but this seems, again, to be debug leftovers. */
|
/* Ensure that if we show a charging icon, we stop showing it when we're done. */
|
||||||
const u32 required_voltage = ac_ok ? 4000 : 3650;
|
|
||||||
return battery_voltage >= required_voltage;
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBatteryResult LoopCheckBattery(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit, bool reboot_on_power_button_pressed, bool succeed_on_sufficient_battery, bool shutdown_on_full_battery, bool can_show_battery_icon, bool can_show_charging_icon) {
|
|
||||||
bool is_showing_charging_icon = false;
|
bool is_showing_charging_icon = false;
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
if (is_showing_charging_icon) {
|
if (is_showing_charging_icon) {
|
||||||
EndShowChargingIcon();
|
boot::EndShowChargingIcon();
|
||||||
|
is_showing_charging_icon = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (can_show_charging_icon) {
|
/* Show the charging display, if we should. */
|
||||||
size_t battery_percentage;
|
if (show_charging_display) {
|
||||||
if (R_FAILED(battery_driver->GetBatteryPercentage(&battery_percentage))) {
|
/* Get the raw battery charge. */
|
||||||
|
float raw_battery_charge;
|
||||||
|
if (R_FAILED(this->battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) {
|
||||||
return CheckBatteryResult::Shutdown;
|
return CheckBatteryResult::Shutdown;
|
||||||
}
|
}
|
||||||
StartShowChargingIcon(battery_percentage, true);
|
|
||||||
|
/* Display the battery with the appropriate percentage. */
|
||||||
|
const auto battery_charge = powctl::impl::ConvertBatteryChargePercentage(raw_battery_charge);
|
||||||
|
boot::StartShowChargingIcon(battery_charge);
|
||||||
is_showing_charging_icon = true;
|
is_showing_charging_icon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Loop, checking the battery status. */
|
||||||
|
TimeSpan last_progress_time = TimeSpan(0);
|
||||||
while (true) {
|
while (true) {
|
||||||
double battery_charge;
|
/* Get the raw battery charge. */
|
||||||
if (R_FAILED(battery_driver->GetSocRep(&battery_charge))) {
|
float raw_battery_charge;
|
||||||
|
if (R_FAILED(this->battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) {
|
||||||
return CheckBatteryResult::Shutdown;
|
return CheckBatteryResult::Shutdown;
|
||||||
}
|
}
|
||||||
if (succeed_on_sufficient_battery && battery_charge >= 3.0) {
|
|
||||||
return CheckBatteryResult::Success;
|
|
||||||
} else if (shutdown_on_full_battery && battery_charge >= 99.0) {
|
|
||||||
return CheckBatteryResult::Shutdown;
|
|
||||||
} else {
|
|
||||||
/* Nintendo has logic for checking a value every 10 seconds. */
|
|
||||||
/* They never do anything with this value though, so it's probably just leftovers from debug? */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Get the average vcell. */
|
||||||
|
int battery_voltage;
|
||||||
|
if (R_FAILED(this->battery_driver.GetAverageVCell(std::addressof(battery_voltage)))) {
|
||||||
|
return CheckBatteryResult::Shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get whether we're connected to charger. */
|
||||||
bool ac_ok;
|
bool ac_ok;
|
||||||
if (R_FAILED(pmic_driver->GetAcOk(&ac_ok))) {
|
if (R_FAILED((boot::PmicDriver().GetAcOk(std::addressof(ac_ok))))) {
|
||||||
return CheckBatteryResult::Shutdown;
|
return CheckBatteryResult::Shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 battery_voltage;
|
/* Decide on a battery voltage threshold. */
|
||||||
if (R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) {
|
const auto battery_voltage_threshold = ac_ok ? BatteryVoltageThresholdConnected : BatteryVoltageThresholdDisconnected;
|
||||||
return CheckBatteryResult::Shutdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (succeed_on_sufficient_battery && IsSufficientBattery(battery_voltage, ac_ok)) {
|
/* Check if we should return. */
|
||||||
return CheckBatteryResult::Success;
|
if (return_on_enough_battery) {
|
||||||
}
|
if (raw_battery_charge >= BatteryLevelThresholdForBoot || battery_voltage >= battery_voltage_threshold) {
|
||||||
|
this->PrintBatteryStatus(raw_battery_charge, battery_voltage, battery_voltage_threshold);
|
||||||
if (!ac_ok) {
|
return CheckBatteryResult::Success;
|
||||||
if (can_show_battery_icon && !is_showing_charging_icon) {
|
|
||||||
ShowLowBatteryIcon();
|
|
||||||
}
|
}
|
||||||
return CheckBatteryResult::Shutdown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reboot_on_power_button_pressed) {
|
/* Otherwise, check if we should shut down. */
|
||||||
bool power_button_pressed;
|
if (shutdown_on_full_battery) {
|
||||||
if (R_FAILED(pmic_driver->GetPowerButtonPressed(&power_button_pressed))) {
|
if (raw_battery_charge >= BatteryLevelThresholdForFullCharge || this->IsChargeDone()) {
|
||||||
return CheckBatteryResult::Shutdown;
|
return CheckBatteryResult::Shutdown;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform periodic printing. */
|
||||||
|
constexpr TimeSpan PrintProgressInterval = TimeSpan::FromSeconds(10);
|
||||||
|
const auto cur_time = os::ConvertToTimeSpan(os::GetSystemTick());
|
||||||
|
if ((cur_time - last_progress_time) >= PrintProgressInterval) {
|
||||||
|
last_progress_time = cur_time;
|
||||||
|
this->PrintBatteryStatus(raw_battery_charge, battery_voltage, battery_voltage_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we've gotten to this point, we have insufficient battery to boot. If we aren't charging, show low battery and shutdown. */
|
||||||
|
if (!ac_ok) {
|
||||||
|
this->PrintBatteryStatus(raw_battery_charge, battery_voltage, battery_voltage_threshold);
|
||||||
|
if (show_display && !is_showing_charging_icon) {
|
||||||
|
boot::ShowLowBatteryIcon();
|
||||||
|
}
|
||||||
|
return CheckBatteryResult::Shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we should reboot due to a power button press. */
|
||||||
|
if (reboot_on_power_button_press) {
|
||||||
|
/* Get the power button value. */
|
||||||
|
bool power_button_pressed;
|
||||||
|
if (R_FAILED((boot::PmicDriver().GetPowerButtonPressed(std::addressof(power_button_pressed))))) {
|
||||||
|
return CheckBatteryResult::Shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the press (or not). */
|
||||||
if (power_button_pressed) {
|
if (power_button_pressed) {
|
||||||
return CheckBatteryResult::Reboot;
|
return CheckBatteryResult::Reboot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_show_battery_icon && !is_showing_charging_icon) {
|
/* If we got to this point, we should show the low-battery charging screen. */
|
||||||
StartShowChargingIcon(1, false);
|
if (show_display && !is_showing_charging_icon) {
|
||||||
|
boot::StartShowLowBatteryChargingIcon();
|
||||||
is_showing_charging_icon = true;
|
is_showing_charging_icon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
svcSleepThread(20'000'000ul);
|
/* Wait a bit before checking again. */
|
||||||
UpdateCharger(pmic_driver, charger_driver, battery_driver, params, charge_voltage_limit);
|
constexpr auto BatteryChargeCheckInterval = TimeSpan::FromMilliSeconds(20);
|
||||||
|
os::SleepThread(BatteryChargeCheckInterval);
|
||||||
|
|
||||||
|
/* Update the charger. */
|
||||||
|
this->UpdateCharger();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckBatteryCharge() {
|
void CheckBatteryCharge() {
|
||||||
PmicDriver pmic_driver;
|
/* Open a sessions for the charger/battery. */
|
||||||
BatteryDriver battery_driver;
|
boot::ChargerDriver charger_driver;
|
||||||
ChargerDriver charger_driver;
|
boot::BatteryDriver battery_driver;
|
||||||
|
|
||||||
if (R_FAILED(battery_driver.InitializeBatteryParameters())) {
|
/* Check if the battery is removed. */
|
||||||
pmic_driver.ShutdownSystem();
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
bool removed;
|
bool removed = false;
|
||||||
if (R_FAILED(battery_driver.IsBatteryRemoved(&removed)) || removed) {
|
if (R_FAILED(battery_driver.IsBatteryRemoved(std::addressof(removed))) || removed) {
|
||||||
pmic_driver.ShutdownSystem();
|
boot::ShutdownSystem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 boot_reason = GetBootReason();
|
/* Get the boot reason. */
|
||||||
bq24193::InputCurrentLimit input_current_limit;
|
const auto boot_reason = boot::GetBootReason();
|
||||||
if (R_FAILED(charger_driver.Initialize(boot_reason != 4)) || R_FAILED(charger_driver.GetInputCurrentLimit(&input_current_limit))) {
|
|
||||||
pmic_driver.ShutdownSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input_current_limit <= bq24193::InputCurrentLimit_150mA) {
|
/* Initialize the charger driver. */
|
||||||
charger_driver.SetChargerConfiguration(bq24193::ChargerConfiguration_ChargeDisable);
|
if (R_FAILED(charger_driver.Initialize(boot_reason != spl::BootReason_RtcAlarm2)))
|
||||||
pmic_driver.ShutdownSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
const BatteryChargeParameters *params = GetBatteryChargeParameters(GetBatteryVersion());
|
/* Check that the charger input limit is greater than 150 milli-amps. */
|
||||||
u32 charge_voltage_limit = params->charge_voltage_limit_default;
|
{
|
||||||
CheckBatteryResult check_result;
|
int input_current_limit_ma;
|
||||||
if (boot_reason == 4) {
|
if (R_FAILED(charger_driver.GetInputCurrentLimit(std::addressof(input_current_limit_ma)))) {
|
||||||
if (R_FAILED(charger_driver.GetChargeVoltageLimit(&charge_voltage_limit))) {
|
boot::ShutdownSystem();
|
||||||
pmic_driver.ShutdownSystem();
|
|
||||||
}
|
}
|
||||||
UpdateCharger(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit);
|
|
||||||
check_result = LoopCheckBattery(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit, true, false, true, false, false);
|
if (input_current_limit_ma <= 150) {
|
||||||
|
charger_driver.SetChargerConfiguration(powctl::ChargerConfiguration_ChargeDisable);
|
||||||
|
boot::ShutdownSystem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the charge parameters. */
|
||||||
|
const auto &charge_parameters = powctl::driver::impl::GetChargeParameters();
|
||||||
|
|
||||||
|
/* Get the charge voltage limit. */
|
||||||
|
int charge_voltage_limit_mv;
|
||||||
|
if (boot_reason != spl::BootReason_RtcAlarm2) {
|
||||||
|
charge_voltage_limit_mv = charge_parameters.default_charge_voltage_limit;
|
||||||
} else {
|
} else {
|
||||||
UpdateCharger(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit);
|
if (R_FAILED(charger_driver.GetChargeVoltageLimit(std::addressof(charge_voltage_limit_mv)))) {
|
||||||
if (boot_reason == 1) {
|
boot::ShutdownSystem();
|
||||||
check_result = LoopCheckBattery(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit, true, true, false, true, true);
|
|
||||||
} else {
|
|
||||||
check_result = LoopCheckBattery(&pmic_driver, &charger_driver, &battery_driver, params, charge_voltage_limit, false, true, false, true, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (check_result) {
|
/* Create and update a battery checker. */
|
||||||
|
BatteryChecker battery_checker(charger_driver, battery_driver, charge_parameters, charge_voltage_limit_mv);
|
||||||
|
battery_checker.UpdateCharger();
|
||||||
|
|
||||||
|
/* Set the display brightness to 25%. */
|
||||||
|
boot::SetDisplayBrightness(25);
|
||||||
|
|
||||||
|
/* Check the battery. */
|
||||||
|
const CheckBatteryResult check_result = battery_checker.LoopCheckBattery(boot_reason);
|
||||||
|
|
||||||
|
/* Set the display brightness to 100%. */
|
||||||
|
boot::SetDisplayBrightness(100);
|
||||||
|
|
||||||
|
/* Handle the check result. */
|
||||||
|
switch (check_result) {
|
||||||
case CheckBatteryResult::Success:
|
case CheckBatteryResult::Success:
|
||||||
break;
|
break;
|
||||||
case CheckBatteryResult::Shutdown:
|
case CheckBatteryResult::Shutdown:
|
||||||
pmic_driver.ShutdownSystem();
|
boot::ShutdownSystem();
|
||||||
break;
|
break;
|
||||||
case CheckBatteryResult::Reboot:
|
case CheckBatteryResult::Reboot:
|
||||||
RebootSystem();
|
boot::RebootSystem();
|
||||||
break;
|
break;
|
||||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "boot_clock_initial_configuration.hpp"
|
#include "boot_clock_initial_configuration.hpp"
|
||||||
#include "boot_pmc_wrapper.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400;
|
||||||
|
|
||||||
/* Convenience definitions. */
|
/* Convenience definitions. */
|
||||||
constexpr u32 InitialClockOutMask1x = 0x00C4;
|
constexpr u32 InitialClockOutMask1x = 0x00C4;
|
||||||
constexpr u32 InitialClockOutMask6x = 0xC4C4;
|
constexpr u32 InitialClockOutMask6x = 0xC4C4;
|
||||||
|
@ -30,7 +31,7 @@ namespace ams::boot {
|
||||||
void SetInitialClockConfiguration() {
|
void SetInitialClockConfiguration() {
|
||||||
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
|
||||||
const u32 mask = hos::GetVersion() >= hos::Version_6_0_0 ? InitialClockOutMask6x : InitialClockOutMask1x;
|
const u32 mask = hos::GetVersion() >= hos::Version_6_0_0 ? InitialClockOutMask6x : InitialClockOutMask1x;
|
||||||
WritePmcRegister(PmcBase + APBDEV_PMC_CLK_OUT_CNTRL, mask, mask);
|
dd::ReadModifyWriteIoRegister(PmcBase + APBDEV_PMC_CLK_OUT_CNTRL, mask, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "boot_display.hpp"
|
#include "boot_display.hpp"
|
||||||
#include "boot_i2c_utils.hpp"
|
#include "boot_i2c_utils.hpp"
|
||||||
#include "boot_pmc_wrapper.hpp"
|
|
||||||
|
|
||||||
#include "boot_registers_di.hpp"
|
#include "boot_registers_di.hpp"
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ namespace ams::boot {
|
||||||
/* Display configuration included into anonymous namespace. */
|
/* Display configuration included into anonymous namespace. */
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#include "boot_display_config.inc"
|
#include "boot_display_config.inc"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +38,8 @@ namespace ams::boot {
|
||||||
constexpr size_t FrameBufferHeight = 1280;
|
constexpr size_t FrameBufferHeight = 1280;
|
||||||
constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
||||||
|
|
||||||
|
constexpr inline dd::PhysicalAddress PmcBase = 0x7000E400;
|
||||||
|
|
||||||
constexpr uintptr_t Disp1Base = 0x54200000ul;
|
constexpr uintptr_t Disp1Base = 0x54200000ul;
|
||||||
constexpr uintptr_t DsiBase = 0x54300000ul;
|
constexpr uintptr_t DsiBase = 0x54300000ul;
|
||||||
constexpr uintptr_t ClkRstBase = 0x60006000ul;
|
constexpr uintptr_t ClkRstBase = 0x60006000ul;
|
||||||
|
@ -68,19 +69,20 @@ namespace ams::boot {
|
||||||
/* Types. */
|
/* Types. */
|
||||||
|
|
||||||
/* Globals. */
|
/* Globals. */
|
||||||
bool g_is_display_intialized = false;
|
constinit bool g_is_display_intialized = false;
|
||||||
u32 *g_frame_buffer = nullptr;
|
constinit u32 *g_frame_buffer = nullptr;
|
||||||
spl::SocType g_soc_type = spl::SocType_Erista;
|
constinit spl::SocType g_soc_type = spl::SocType_Erista;
|
||||||
u32 g_lcd_vendor = 0;
|
constinit u32 g_lcd_vendor = 0;
|
||||||
Handle g_dc_das_hnd = INVALID_HANDLE;
|
constinit Handle g_dc_das_hnd = INVALID_HANDLE;
|
||||||
u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize];
|
constinit int g_display_brightness = 100;
|
||||||
|
constinit u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize];
|
||||||
|
|
||||||
uintptr_t g_disp1_regs = 0;
|
constinit uintptr_t g_disp1_regs = 0;
|
||||||
uintptr_t g_dsi_regs = 0;
|
constinit uintptr_t g_dsi_regs = 0;
|
||||||
uintptr_t g_clk_rst_regs = 0;
|
constinit uintptr_t g_clk_rst_regs = 0;
|
||||||
uintptr_t g_gpio_regs = 0;
|
constinit uintptr_t g_gpio_regs = 0;
|
||||||
uintptr_t g_apb_misc_regs = 0;
|
constinit uintptr_t g_apb_misc_regs = 0;
|
||||||
uintptr_t g_mipi_cal_regs = 0;
|
constinit uintptr_t g_mipi_cal_regs = 0;
|
||||||
|
|
||||||
/* Helper functions. */
|
/* Helper functions. */
|
||||||
void InitializeRegisterBaseAddresses() {
|
void InitializeRegisterBaseAddresses() {
|
||||||
|
@ -119,9 +121,9 @@ namespace ams::boot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes))
|
#define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes))
|
||||||
#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko))
|
#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko))
|
||||||
#define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, util::size(writes))
|
#define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, util::size(writes))
|
||||||
|
|
||||||
void InitializeFrameBuffer() {
|
void InitializeFrameBuffer() {
|
||||||
if (g_frame_buffer != nullptr) {
|
if (g_frame_buffer != nullptr) {
|
||||||
|
@ -217,8 +219,8 @@ namespace ams::boot {
|
||||||
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, 0xA);
|
reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, 0xA);
|
||||||
|
|
||||||
/* DPD idle. */
|
/* DPD idle. */
|
||||||
WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, 0x40000000);
|
dd::WriteIoRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, 0x40000000);
|
||||||
WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, 0x40000000);
|
dd::WriteIoRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, 0x40000000);
|
||||||
|
|
||||||
/* Configure LCD pinmux tristate + passthrough. */
|
/* Configure LCD pinmux tristate + passthrough. */
|
||||||
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE)));
|
||||||
|
@ -502,4 +504,8 @@ namespace ams::boot {
|
||||||
g_is_display_intialized = false;
|
g_is_display_intialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetDisplayBrightness(int percentage) {
|
||||||
|
g_display_brightness = percentage;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,4 +23,6 @@ namespace ams::boot {
|
||||||
void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img);
|
void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img);
|
||||||
void FinalizeDisplay();
|
void FinalizeDisplay();
|
||||||
|
|
||||||
|
void SetDisplayBrightness(int percentage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
#include "boot_pmc_wrapper.hpp"
|
|
||||||
|
|
||||||
namespace ams::boot {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/* Convenience definitions. */
|
|
||||||
constexpr dd::PhysicalAddress PmcPhysStart = 0x7000E400;
|
|
||||||
constexpr dd::PhysicalAddress PmcPhysLast = 0x7000EFFF;
|
|
||||||
|
|
||||||
/* Helpers. */
|
|
||||||
bool IsValidPmcAddress(dd::PhysicalAddress phys_addr) {
|
|
||||||
return util::IsAligned(phys_addr, alignof(u32)) && PmcPhysStart <= phys_addr && phys_addr <= PmcPhysLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 ReadWriteRegisterImpl(dd::PhysicalAddress phys_addr, u32 value, u32 mask) {
|
|
||||||
u32 out_value;
|
|
||||||
R_ABORT_UNLESS(spl::smc::ConvertResult(spl::smc::AtmosphereReadWriteRegister(phys_addr, mask, value, &out_value)));
|
|
||||||
return out_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 ReadPmcRegister(dd::PhysicalAddress phys_addr) {
|
|
||||||
AMS_ABORT_UNLESS(IsValidPmcAddress(phys_addr));
|
|
||||||
return ReadWriteRegisterImpl(phys_addr, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WritePmcRegister(dd::PhysicalAddress phys_addr, u32 value, u32 mask) {
|
|
||||||
AMS_ABORT_UNLESS(IsValidPmcAddress(phys_addr));
|
|
||||||
ReadWriteRegisterImpl(phys_addr, value, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -20,90 +20,87 @@
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
|
||||||
void PmicDriver::ShutdownSystem() {
|
void PmicDriver::ShutdownSystem() {
|
||||||
R_ABORT_UNLESS(this->ShutdownSystem(false));
|
this->ShutdownSystem(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PmicDriver::RebootSystem() {
|
void PmicDriver::RebootSystem() {
|
||||||
R_ABORT_UNLESS(this->ShutdownSystem(true));
|
this->ShutdownSystem(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PmicDriver::GetAcOk(bool *out) {
|
Result PmicDriver::GetAcOk(bool *out) {
|
||||||
u8 power_status;
|
u8 power_status;
|
||||||
R_TRY(this->GetPowerStatus(&power_status));
|
R_TRY(this->GetPowerStatus(std::addressof(power_status)));
|
||||||
*out = (power_status & 0x02) != 0;
|
*out = (power_status & 0x02) != 0;
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PmicDriver::GetPowerIntr(u8 *out) {
|
Result PmicDriver::GetOnOffIrq(u8 *out) {
|
||||||
const u8 addr = 0x0B;
|
const u8 addr = 0x0B;
|
||||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PmicDriver::GetPowerStatus(u8 *out) {
|
Result PmicDriver::GetPowerStatus(u8 *out) {
|
||||||
const u8 addr = 0x15;
|
const u8 addr = 0x15;
|
||||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PmicDriver::GetNvErc(u8 *out) {
|
Result PmicDriver::GetNvErc(u8 *out) {
|
||||||
const u8 addr = 0x0C;
|
const u8 addr = 0x0C;
|
||||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PmicDriver::GetPowerButtonPressed(bool *out) {
|
Result PmicDriver::GetPowerButtonPressed(bool *out) {
|
||||||
u8 power_intr;
|
u8 on_off_irq;
|
||||||
R_TRY(this->GetPowerIntr(&power_intr));
|
R_TRY(this->GetOnOffIrq(std::addressof(on_off_irq)));
|
||||||
*out = (power_intr & 0x08) != 0;
|
*out = (on_off_irq & 0x08) != 0;
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PmicDriver::ShutdownSystem(bool reboot) {
|
void PmicDriver::ShutdownSystem(bool reboot) {
|
||||||
const u8 on_off_1_addr = 0x41;
|
const u8 on_off_1_addr = 0x41;
|
||||||
const u8 on_off_2_addr = 0x42;
|
const u8 on_off_2_addr = 0x42;
|
||||||
|
|
||||||
/* Get value, set or clear software reset mask. */
|
/* Get value, set or clear software reset mask. */
|
||||||
u8 on_off_2_val = 0;
|
u8 on_off_2_val = 0;
|
||||||
R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)));
|
R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr)));
|
||||||
if (reboot) {
|
if (reboot) {
|
||||||
on_off_2_val |= 0x80;
|
on_off_2_val |= 0x80;
|
||||||
} else {
|
} else {
|
||||||
on_off_2_val &= ~0x80;
|
on_off_2_val &= ~0x80;
|
||||||
}
|
}
|
||||||
R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)));
|
R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr)));
|
||||||
|
|
||||||
/* Get value, set software reset mask. */
|
/* Get value, set software reset mask. */
|
||||||
u8 on_off_1_val = 0;
|
u8 on_off_1_val = 0;
|
||||||
R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)));
|
R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr)));
|
||||||
on_off_1_val |= 0x80;
|
on_off_1_val |= 0x80;
|
||||||
|
|
||||||
/* Finalize the battery on non-Calcio. */
|
/* Finalize the battery on non-Calcio. */
|
||||||
if (spl::GetHardwareType() != spl::HardwareType::Calcio) {
|
if (spl::GetHardwareType() != spl::HardwareType::Calcio) {
|
||||||
BatteryDriver battery_driver;
|
BatteryDriver battery_driver;
|
||||||
this->FinalizeBattery(&battery_driver);
|
this->FinalizeBattery(battery_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actually write the value to trigger shutdown/reset. */
|
/* Actually write the value to trigger shutdown/reset. */
|
||||||
R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)));
|
R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr)));
|
||||||
|
|
||||||
/* Allow up to 5 seconds for shutdown/reboot to take place. */
|
/* Allow up to 5 seconds for shutdown/reboot to take place. */
|
||||||
svcSleepThread(5'000'000'000ul);
|
os::SleepThread(TimeSpan::FromSeconds(5));
|
||||||
AMS_ABORT_UNLESS(false);
|
AMS_ABORT("Shutdown failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PmicDriver::FinalizeBattery(BatteryDriver *battery_driver) {
|
void PmicDriver::FinalizeBattery(BatteryDriver &battery_driver) {
|
||||||
/* Set shutdown timer. */
|
|
||||||
battery_driver->SetShutdownTimer();
|
|
||||||
|
|
||||||
/* Get whether shutdown is enabled. */
|
/* Get whether shutdown is enabled. */
|
||||||
bool shutdown_enabled;
|
bool shutdown_enabled;
|
||||||
if (R_FAILED(battery_driver->GetShutdownEnabled(&shutdown_enabled))) {
|
if (R_FAILED(battery_driver.IsI2cShutdownEnabled(std::addressof(shutdown_enabled)))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On Hoag, we don't want to use the desired shutdown value when battery charged. */
|
/* On Hoag, we don't want to use the desired shutdown value when battery charged. */
|
||||||
bool use_desired_shutdown = true;
|
bool use_desired_shutdown = true;
|
||||||
if (spl::GetHardwareType() == spl::HardwareType::Hoag) {
|
if (spl::GetHardwareType() == spl::HardwareType::Hoag) {
|
||||||
double battery_charge;
|
float battery_charge_raw;
|
||||||
if (R_FAILED(battery_driver->GetSocRep(&battery_charge)) || battery_charge >= 80.0) {
|
if (R_FAILED(battery_driver.GetSocRep(std::addressof(battery_charge_raw))) || battery_charge_raw >= 80.0) {
|
||||||
use_desired_shutdown = false;
|
use_desired_shutdown = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +116,7 @@ namespace ams::boot {
|
||||||
desired_shutdown_enabled &= use_desired_shutdown;
|
desired_shutdown_enabled &= use_desired_shutdown;
|
||||||
|
|
||||||
if (shutdown_enabled != desired_shutdown_enabled) {
|
if (shutdown_enabled != desired_shutdown_enabled) {
|
||||||
battery_driver->SetShutdownEnabled(desired_shutdown_enabled);
|
battery_driver.SetI2cShutdownEnabled(desired_shutdown_enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,13 @@ namespace ams::boot {
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Result GetPowerStatus(u8 *out);
|
Result GetPowerStatus(u8 *out);
|
||||||
Result ShutdownSystem(bool reboot);
|
void ShutdownSystem(bool reboot);
|
||||||
void FinalizeBattery(BatteryDriver *battery_driver);
|
void FinalizeBattery(BatteryDriver &battery_driver);
|
||||||
public:
|
public:
|
||||||
void ShutdownSystem();
|
void ShutdownSystem();
|
||||||
void RebootSystem();
|
void RebootSystem();
|
||||||
Result GetAcOk(bool *out);
|
Result GetAcOk(bool *out);
|
||||||
Result GetPowerIntr(u8 *out);
|
Result GetOnOffIrq(u8 *out);
|
||||||
Result GetNvErc(u8 *out);
|
Result GetNvErc(u8 *out);
|
||||||
Result GetPowerButtonPressed(bool *out);
|
Result GetPowerButtonPressed(bool *out);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "boot_power_utils.hpp"
|
#include "boot_power_utils.hpp"
|
||||||
|
#include "boot_pmic_driver.hpp"
|
||||||
#include "fusee-primary_bin.h"
|
#include "fusee-primary_bin.h"
|
||||||
|
|
||||||
namespace ams::boot {
|
namespace ams::boot {
|
||||||
|
@ -65,7 +66,16 @@ namespace ams::boot {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RebootSystem() {
|
void RebootSystem() {
|
||||||
DoRebootToPayload(nullptr);
|
if (spl::GetSocType() == spl::SocType_Erista) {
|
||||||
|
DoRebootToPayload(nullptr);
|
||||||
|
} else {
|
||||||
|
/* On Mariko, we can't reboot to payload, so we should just do a reboot. */
|
||||||
|
PmicDriver().RebootSystem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownSystem() {
|
||||||
|
PmicDriver().ShutdownSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInitialRebootPayload() {
|
void SetInitialRebootPayload() {
|
||||||
|
|
|
@ -29,8 +29,8 @@ namespace ams::boot {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowSplashScreen() {
|
void ShowSplashScreen() {
|
||||||
const u32 boot_reason = GetBootReason();
|
const auto boot_reason = GetBootReason();
|
||||||
if (boot_reason == 1 || boot_reason == 4) {
|
if (boot_reason == spl::BootReason_AcOk || boot_reason == spl::BootReason_RtcAlarm2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ namespace ams::boot {
|
||||||
{
|
{
|
||||||
/* Splash screen is shown for 2 seconds. */
|
/* Splash screen is shown for 2 seconds. */
|
||||||
ShowDisplay(SplashScreenX, SplashScreenY, SplashScreenW, SplashScreenH, SplashScreen);
|
ShowDisplay(SplashScreenX, SplashScreenY, SplashScreenW, SplashScreenH, SplashScreen);
|
||||||
svcSleepThread(2'000'000'000ul);
|
os::SleepThread(TimeSpan::FromSeconds(2));
|
||||||
}
|
}
|
||||||
FinalizeDisplay();
|
FinalizeDisplay();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue