Device migrations and driver improvements (#576)

This commit is contained in:
Ken Van Hoeylandt
2026-07-22 21:11:12 +02:00
committed by GitHub
parent 2fbc44466a
commit a3fda9ad8f
100 changed files with 707 additions and 3838 deletions
@@ -3,3 +3,86 @@ description: X-Powers AXP2101 power management IC
include: ["i2c-device.yaml"]
compatible: "x-powers,axp2101"
properties:
aldo1-millivolt:
type: int
default: 0
description: ALDO1 output voltage in mV (500-3500, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
aldo1-enabled:
type: boolean
default: false
description: Enable ALDO1 at driver start.
aldo2-millivolt:
type: int
default: 0
description: ALDO2 output voltage in mV (500-3500, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
aldo2-enabled:
type: boolean
default: false
description: Enable ALDO2 at driver start.
aldo3-millivolt:
type: int
default: 0
description: ALDO3 output voltage in mV (500-3500, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
aldo3-enabled:
type: boolean
default: false
description: Enable ALDO3 at driver start.
aldo4-millivolt:
type: int
default: 0
description: ALDO4 output voltage in mV (500-3500, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
aldo4-enabled:
type: boolean
default: false
description: Enable ALDO4 at driver start.
bldo1-millivolt:
type: int
default: 0
description: BLDO1 output voltage in mV (500-3500, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
bldo1-enabled:
type: boolean
default: false
description: Enable BLDO1 at driver start.
bldo2-millivolt:
type: int
default: 0
description: BLDO2 output voltage in mV (500-3500, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
bldo2-enabled:
type: boolean
default: false
description: Enable BLDO2 at driver start.
cpusldo-millivolt:
type: int
default: 0
description: CPUSLDO output voltage in mV (500-1400, step 50), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
cpusldo-enabled:
type: boolean
default: false
description: Enable CPUSLDO at driver start.
dldo1-millivolt:
type: int
default: 0
description: DLDO1 output voltage in mV (500-3400, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
dldo1-enabled:
type: boolean
default: false
description: Enable DLDO1 at driver start.
dldo2-millivolt:
type: int
default: 0
description: DLDO2 output voltage in mV (500-3400, step 100), applied at driver start if
non-zero. 0 leaves the channel's voltage untouched.
dldo2-enabled:
type: boolean
default: false
description: Enable DLDO2 at driver start.
@@ -15,6 +15,29 @@ extern "C" {
struct Axp2101Config {
/** Address on bus */
uint8_t address;
/** LDOx output voltage in mV, applied at driver start when non-zero, independently of the
* matching xEnabled flag. 0 leaves the channel's voltage untouched. Field order here MUST
* match the property order in bindings/x-powers,axp2101.yaml: the devicetree compiler
* emits positional (non-designated) initializers, so a mismatch silently shifts every
* value into the wrong field. */
uint16_t aldo1_millivolt;
bool aldo1_enabled;
uint16_t aldo2_millivolt;
bool aldo2_enabled;
uint16_t aldo3_millivolt;
bool aldo3_enabled;
uint16_t aldo4_millivolt;
bool aldo4_enabled;
uint16_t bldo1_millivolt;
bool bldo1_enabled;
uint16_t bldo2_millivolt;
bool bldo2_enabled;
uint16_t cpusldo_millivolt;
bool cpusldo_enabled;
uint16_t dldo1_millivolt;
bool dldo1_enabled;
uint16_t dldo2_millivolt;
bool dldo2_enabled;
};
/** Switchable/adjustable DCDC (buck) converters of the AXP2101. */
+57 -8
View File
@@ -49,15 +49,24 @@ struct Axp2101VoltRange {
uint8_t code_base;
};
/** Validates millivolts against a single known range and encodes it. No search: caller has
* already picked which range applies (e.g. by channel). */
static error_t encode_single_range(uint16_t millivolts, const Axp2101VoltRange& range, uint8_t* out_code) {
if (millivolts < range.min || millivolts > range.max || (millivolts - range.min) % range.step != 0U) {
return ERROR_INVALID_ARGUMENT;
}
*out_code = static_cast<uint8_t>(range.code_base + (millivolts - range.min) / range.step);
return ERROR_NONE;
}
/** Finds which of several (possibly non-contiguous) sub-ranges of a single channel contains
* millivolts, and encodes it. Only meaningful when ranges all belong to the SAME channel
* (e.g. DCDC3's three piecewise sub-ranges) - never pass ranges from different channels,
* since their spans can legitimately overlap and this would silently pick the first match. */
static error_t encode_ranged_voltage(uint16_t millivolts, const Axp2101VoltRange* ranges, size_t range_count, uint8_t* out_code) {
for (size_t i = 0; i < range_count; i++) {
const Axp2101VoltRange& range = ranges[i];
if (millivolts >= range.min && millivolts <= range.max) {
if ((millivolts - range.min) % range.step != 0U) {
return ERROR_INVALID_ARGUMENT;
}
*out_code = static_cast<uint8_t>(range.code_base + (millivolts - range.min) / range.step);
return ERROR_NONE;
if (millivolts >= ranges[i].min && millivolts <= ranges[i].max) {
return encode_single_range(millivolts, ranges[i], out_code);
}
}
return ERROR_INVALID_ARGUMENT;
@@ -253,8 +262,9 @@ error_t axp2101_set_ldo_voltage(Device* device, Axp2101Ldo ldo, uint16_t millivo
};
uint8_t code;
error_t err = encode_ranged_voltage(millivolts, &LDO_RANGE[ldo], 1, &code);
error_t err = encode_single_range(millivolts, LDO_RANGE[ldo], &code);
if (err != ERROR_NONE) {
LOG_E(TAG, "Failed to encode %u mV", millivolts);
return err;
}
@@ -518,6 +528,45 @@ static error_t start(Device* device) {
return error;
}
// All 9 LDO channels: voltage and enable states are applied independently if configured.
// Boards that need it enable/voltage-set the channel via config instead of per-board imperative code.
// Order matches enum Axp2101Ldo.
static constexpr Axp2101Ldo LDO_CHANNELS[9] = {
AXP2101_ALDO1, AXP2101_ALDO2, AXP2101_ALDO3, AXP2101_ALDO4,
AXP2101_BLDO1, AXP2101_BLDO2, AXP2101_CPUSLDO, AXP2101_DLDO1, AXP2101_DLDO2,
};
static constexpr const char* LDO_NAMES[9] = {
"ALDO1", "ALDO2", "ALDO3", "ALDO4", "BLDO1", "BLDO2", "CPUSLDO", "DLDO1", "DLDO2",
};
const auto* config = GET_CONFIG(device);
const uint16_t ldo_millivolts[9] = {
config->aldo1_millivolt, config->aldo2_millivolt, config->aldo3_millivolt, config->aldo4_millivolt,
config->bldo1_millivolt, config->bldo2_millivolt, config->cpusldo_millivolt,
config->dldo1_millivolt, config->dldo2_millivolt,
};
const bool ldo_enabled[9] = {
config->aldo1_enabled, config->aldo2_enabled, config->aldo3_enabled, config->aldo4_enabled,
config->bldo1_enabled, config->bldo2_enabled, config->cpusldo_enabled,
config->dldo1_enabled, config->dldo2_enabled,
};
for (size_t i = 0; i < 9; i++) {
if (ldo_millivolts[i] != 0) {
error_t err = axp2101_set_ldo_voltage(device, LDO_CHANNELS[i], ldo_millivolts[i]);
if (err != ERROR_NONE) {
LOG_E(TAG, "Failed to set %s voltage", LDO_NAMES[i]);
return err;
}
}
if (ldo_enabled[i]) {
error_t err = axp2101_set_ldo_enabled(device, LDO_CHANNELS[i], true);
if (err != ERROR_NONE) {
LOG_E(TAG, "Failed to enable %s", LDO_NAMES[i]);
return err;
}
}
}
auto* internal = new(std::nothrow) Axp2101Internal();
if (internal == nullptr) {
return ERROR_OUT_OF_MEMORY;