diff --git a/Devices/m5stack-core2/CMakeLists.txt b/Devices/m5stack-core2/CMakeLists.txt index 6e986ba7e..a7d3e6712 100644 --- a/Devices/m5stack-core2/CMakeLists.txt +++ b/Devices/m5stack-core2/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilityKernel axp192-module + REQUIRES TactilityKernel ) diff --git a/Devices/m5stack-core2/device.properties b/Devices/m5stack-core2/device.properties index 8f887a003..cfaaf47d0 100644 --- a/Devices/m5stack-core2/device.properties +++ b/Devices/m5stack-core2/device.properties @@ -21,3 +21,5 @@ display.dpi=200 cdn.warningMessage=This board implementation concerns the original Core2 hardware and **not** the v1.1 variant lvgl.colorDepth=16 + +sdkconfig.CONFIG_CODEC_DUMMY_SUPPORT=y diff --git a/Devices/m5stack-core2/devicetree.yaml b/Devices/m5stack-core2/devicetree.yaml index f1711cb3b..894ee337e 100644 --- a/Devices/m5stack-core2/devicetree.yaml +++ b/Devices/m5stack-core2/devicetree.yaml @@ -1,8 +1,11 @@ dependencies: - Platforms/platform-esp32 +- Drivers/audio-stream-module +- Drivers/pdm-mic-module +- Drivers/dummy-i2s-amp-module - Drivers/mpu6886-module - Drivers/bm8563-module - Drivers/axp192-module -- Drivers/ft6x36-module +- Drivers/ft5x06-module - Drivers/ili9341-module dts: m5stack,core2.dts diff --git a/Devices/m5stack-core2/m5stack,core2.dts b/Devices/m5stack-core2/m5stack,core2.dts index 840f35429..499df6d1f 100644 --- a/Devices/m5stack-core2/m5stack,core2.dts +++ b/Devices/m5stack-core2/m5stack,core2.dts @@ -6,14 +6,16 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include -#include +#include +#include // Reference: https://docs.m5stack.com/en/core/Core2 / { @@ -50,10 +52,23 @@ axp192 { compatible = "x-powers,axp192"; reg = <0x34>; + dcdc1-enable; // ESP32 + peripherals main 3V3 rail - must stay on + dcdc1-voltage = <3300>; + dcdc3-enable; // LCD backlight + dcdc3-voltage = <3300>; + ldo2-enable; // LCD logic + SD card + ldo2-voltage = <3300>; + // ldo3 (vibration motor) intentionally left disabled + exten-enable; // 5V boost (speaker amp etc.) + gpio1-pwm; // GPIO1 as PWM1 output, drives the notification LED + gpio1-pwm1-duty-cycle = <255>; // 255 = LED off }; + // FT6x36 driver doesn't reliably work when power cycling, + // or when the driver was powering on with its own power supply (not USB-C). + // The driver would not find the device and init would fail. touch { - compatible = "focaltech,ft6x36"; + compatible = "focaltech,ft5x06"; reg = <0x38>; x-max = <320>; y-max = <240>; @@ -96,8 +111,6 @@ }; }; - // NS4168: Speaker and microphone - // TODO: Init microphone via I2C: https://github.com/m5stack/M5Unified/blob/a6256725481f1bc366655fa48cf03b6095e30ad1/src/M5Unified.cpp#L391C19-L391C44 i2s0 { compatible = "espressif,esp32-i2s"; port = ; @@ -106,4 +119,15 @@ pin-data-out = <&gpio0 2 GPIO_FLAG_NONE>; pin-data-in = <&gpio0 34 GPIO_FLAG_NONE>; }; + + speaker0 { + compatible = "nsiway,ns4168"; + i2s = <&i2s0>; + }; + + mic0 { + compatible = "generic,spm1423"; + i2s = <&i2s0>; + channels = <1>; + }; }; diff --git a/Devices/m5stack-core2/source/module.cpp b/Devices/m5stack-core2/source/module.cpp index bedeee431..c1276986c 100644 --- a/Devices/m5stack-core2/source/module.cpp +++ b/Devices/m5stack-core2/source/module.cpp @@ -1,47 +1,15 @@ -#include - -#include -#include -#include +#include #include -#include - extern "C" { -static void configure_axp192(Device* axp192) { - check(axp192_set_rail_voltage(axp192, AXP192_RAIL_LDO2, 3300) == ERROR_NONE); // LCD + SD - check(axp192_set_rail_voltage(axp192, AXP192_RAIL_DCDC3, 3300) == ERROR_NONE); // LCD backlight - - check(axp192_set_rail_enabled(axp192, AXP192_RAIL_LDO2, true) == ERROR_NONE); - check(axp192_set_rail_enabled(axp192, AXP192_RAIL_LDO3, false) == ERROR_NONE); // VIB_MOTOR stop - check(axp192_set_rail_enabled(axp192, AXP192_RAIL_DCDC3, true) == ERROR_NONE); - - check(axp192_set_pwm1_duty_cycle(axp192, 255) == ERROR_NONE); // PWM 255 (LED off) - check(axp192_set_gpio1_pwm1_output(axp192) == ERROR_NONE); // GPIO1: PWM -} - -static void on_device_event(Device* device, DeviceEvent event, void* context) { - (void)context; - if (event == DEVICE_EVENT_STARTED && strcmp(device->name, "axp192") == 0) { - configure_axp192(device); - } -} - -static error_t start() { - device_listener_add(on_device_event, nullptr); - return ERROR_NONE; -} - -static error_t stop() { - device_listener_remove(on_device_event); - return ERROR_NONE; -} - -struct Module m5stack_core2_module = { +// AXP192 rail/GPIO1 bring-up is now devicetree-configured (see m5stack,core2.dts's axp192 node +// and axp192-module's start()), replacing what used to be done by hand here via a +// DEVICE_EVENT_STARTED device_listener. +Module m5stack_core2_module = { .name = "m5stack-core2", - .start = start, - .stop = stop, + .start = [] -> error_t { return ERROR_NONE; }, + .stop = [] -> error_t { return ERROR_NONE; }, .symbols = nullptr, .internal = nullptr }; diff --git a/Devices/m5stack-cores3/devicetree.yaml b/Devices/m5stack-cores3/devicetree.yaml index 5c7affcfb..348e3507e 100644 --- a/Devices/m5stack-cores3/devicetree.yaml +++ b/Devices/m5stack-cores3/devicetree.yaml @@ -1,5 +1,6 @@ dependencies: - Platforms/platform-esp32 +- Drivers/audio-stream-module - Drivers/aw88298-module - Drivers/aw9523b-module - Drivers/axp2101-module diff --git a/Devices/m5stack-stackchan/devicetree.yaml b/Devices/m5stack-stackchan/devicetree.yaml index e735f7d50..4e30a838d 100644 --- a/Devices/m5stack-stackchan/devicetree.yaml +++ b/Devices/m5stack-stackchan/devicetree.yaml @@ -1,5 +1,6 @@ dependencies: - Platforms/platform-esp32 + - Drivers/audio-stream-module - Drivers/aw88298-module - Drivers/aw9523b-module - Drivers/axp2101-module diff --git a/Drivers/axp192-module/bindings/x-powers,axp192.yaml b/Drivers/axp192-module/bindings/x-powers,axp192.yaml index 1f4f6f03f..fd8a7dafc 100644 --- a/Drivers/axp192-module/bindings/x-powers,axp192.yaml +++ b/Drivers/axp192-module/bindings/x-powers,axp192.yaml @@ -3,3 +3,64 @@ description: X-Powers AXP192 power management IC include: ["i2c-device.yaml"] compatible: "x-powers,axp192" + +properties: + dcdc1-voltage: + type: int + default: 0 + description: DCDC1 rail voltage in mV (700-3500). 0 leaves the voltage untouched. + dcdc1-enable: + type: boolean + default: false + description: > + Enable the DCDC1 rail. Unconditionally applied like any other boolean devicetree property - + false actively disables it, so a board whose SoC is powered from DCDC1 must set this. + dcdc2-voltage: + type: int + default: 0 + description: DCDC2 rail voltage in mV (700-2275). 0 leaves the voltage untouched. + dcdc2-enable: + type: boolean + default: false + description: Enable the DCDC2 rail. See dcdc1-enable for why false actively disables it. + dcdc3-voltage: + type: int + default: 0 + description: DCDC3 rail voltage in mV (700-3500). 0 leaves the voltage untouched. + dcdc3-enable: + type: boolean + default: false + description: Enable the DCDC3 rail. See dcdc1-enable for why false actively disables it. + ldo2-voltage: + type: int + default: 0 + description: LDO2 rail voltage in mV (1800-3300). 0 leaves the voltage untouched. + ldo2-enable: + type: boolean + default: false + description: Enable the LDO2 rail. See dcdc1-enable for why false actively disables it. + ldo3-voltage: + type: int + default: 0 + description: LDO3 rail voltage in mV (1800-3300). 0 leaves the voltage untouched. + ldo3-enable: + type: boolean + default: false + description: Enable the LDO3 rail. See dcdc1-enable for why false actively disables it. + exten-enable: + type: boolean + default: false + description: > + Enable the EXTEN output switch. No voltage control (see AXP192_RAIL_EXTEN); see + dcdc1-enable for why false actively disables it. + gpio1-pwm: + type: boolean + default: false + description: Configure GPIO1 as the PWM1 output instead of GPIO/ADC input/output. + gpio1-pwm1-duty-cycle: + type: int + default: 0 + min: 0 + max: 255 + description: > + PWM1 duty cycle (0 = always low, 255 = always high). Only applied when gpio1-pwm is set. diff --git a/Drivers/axp192-module/include/drivers/axp192.h b/Drivers/axp192-module/include/drivers/axp192.h index 40793d351..40f9ae57d 100644 --- a/Drivers/axp192-module/include/drivers/axp192.h +++ b/Drivers/axp192-module/include/drivers/axp192.h @@ -15,6 +15,32 @@ extern "C" { struct Axp192Config { /** Address on bus */ uint8_t address; + /** + * Rail voltage/enable settings, applied once at driver start (see axp192_set_rail_voltage()/ + * axp192_set_rail_enabled()). Each "enable" flag is unconditionally applied - false (the yaml + * default) actively disables the rail, same as every other boolean devicetree property in + * this codebase (e.g. reset-active-high, swap-xy: absence means false, not "leave alone"). + * A board must explicitly set every rail it needs kept on, including ones a board's hardware + * happens to power up with by default (e.g. DCDC1, which is the SoC's own supply on some + * boards) - see m5stack-core2's devicetree for a worked example. Voltage of 0 means "don't + * call axp192_set_rail_voltage() for this rail" (0mV is outside every rail's valid range). + */ + uint16_t dcdc1_voltage_mv; + bool dcdc1_enable; + uint16_t dcdc2_voltage_mv; + bool dcdc2_enable; + uint16_t dcdc3_voltage_mv; + bool dcdc3_enable; + uint16_t ldo2_voltage_mv; + bool ldo2_enable; + uint16_t ldo3_voltage_mv; + bool ldo3_enable; + /** EXTEN has no voltage control (see AXP192_RAIL_EXTEN), hence no exten_voltage_mv field. */ + bool exten_enable; + /** Configures GPIO1 as the PWM1 output (see axp192_set_gpio1_pwm1_output()). */ + bool gpio1_pwm; + /** Applied only when gpio1_pwm is true (see axp192_set_pwm1_duty_cycle()). */ + uint8_t gpio1_pwm1_duty_cycle; }; /** Switchable/adjustable power rails of the AXP192. */ diff --git a/Drivers/axp192-module/source/axp192.cpp b/Drivers/axp192-module/source/axp192.cpp index c32959165..1aca04166 100644 --- a/Drivers/axp192-module/source/axp192.cpp +++ b/Drivers/axp192-module/source/axp192.cpp @@ -12,6 +12,7 @@ #include #define GET_CONFIG(device) (static_cast((device)->config)) +constexpr auto* TAG = "AXP192"; /** Reference: https://github.com/tuupola/axp192 (register map and ADC/voltage formulas) */ static constexpr uint8_t REG_MODE_CHGSTATUS = 0x01U; // bit6: battery is charging @@ -404,10 +405,73 @@ static void destroy_power_supply_child(Device* child) { // endregion +// region Devicetree-configured bring-up + +static error_t apply_rail_config(Device* device, Axp192Rail rail, uint16_t voltage_mv, bool enable) { + if (voltage_mv != 0U) { + error_t error = axp192_set_rail_voltage(device, rail, voltage_mv); + if (error != ERROR_NONE) { + return error; + } + } + return axp192_set_rail_enabled(device, rail, enable); +} + +// Applies the devicetree's rail voltage/enable and GPIO1 PWM settings, replacing what boards +// (e.g. m5stack-core2) used to do by hand via a device_listener after DEVICE_EVENT_STARTED. +static error_t apply_devicetree_config(Device* device) { + const auto* config = GET_CONFIG(device); + + error_t error = apply_rail_config(device, AXP192_RAIL_DCDC1, config->dcdc1_voltage_mv, config->dcdc1_enable); + if (error != ERROR_NONE) { + return error; + } + error = apply_rail_config(device, AXP192_RAIL_DCDC2, config->dcdc2_voltage_mv, config->dcdc2_enable); + if (error != ERROR_NONE) { + return error; + } + error = apply_rail_config(device, AXP192_RAIL_DCDC3, config->dcdc3_voltage_mv, config->dcdc3_enable); + if (error != ERROR_NONE) { + return error; + } + error = apply_rail_config(device, AXP192_RAIL_LDO2, config->ldo2_voltage_mv, config->ldo2_enable); + if (error != ERROR_NONE) { + return error; + } + error = apply_rail_config(device, AXP192_RAIL_LDO3, config->ldo3_voltage_mv, config->ldo3_enable); + if (error != ERROR_NONE) { + return error; + } + error = axp192_set_rail_enabled(device, AXP192_RAIL_EXTEN, config->exten_enable); + if (error != ERROR_NONE) { + return error; + } + + if (config->gpio1_pwm) { + error = axp192_set_pwm1_duty_cycle(device, config->gpio1_pwm1_duty_cycle); + if (error != ERROR_NONE) { + return error; + } + error = axp192_set_gpio1_pwm1_output(device); + if (error != ERROR_NONE) { + return error; + } + } + + return ERROR_NONE; +} + +// endregion + static error_t start(Device* device) { auto* parent = device_get_parent(device); check(device_get_type(parent) == &I2C_CONTROLLER_TYPE); + if (apply_devicetree_config(device) != ERROR_NONE) { + LOG_E(TAG, "Failed to apply devicetree-configured rail/GPIO1 settings"); + return ERROR_RESOURCE; + } + auto* internal = new(std::nothrow) Axp192Internal(); if (internal == nullptr) { return ERROR_OUT_OF_MEMORY;