Device migrations and driver improvements (#576)
This commit is contained in:
committed by
GitHub
parent
2fbc44466a
commit
a3fda9ad8f
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user