I2C sensor fails to initialize when powered by nPM1300 PMIC load switch after Zephyr boot

I’m working on a project using the nRF54L15 SoC together with the nPM1300 Power Management IC.
In my hardware setup:

  • BUCK2 output from the nPM1300 is connected to the LSIN1 pin.

  • The LSOUT1 pin powers an I²C sensor.

At boot time, the SHT4x sensor is not powered because it is connected behind the LDSW1 load switch, which is controlled by firmware to dynamically enable or disable sensor power. During system boot, Zephyr automatically tries to probe the SHT4x as part of its device initialization sequence—this happens before main(). Since the sensor isn’t powered yet, the I²C transactions fail (no ACK from the SHT4x), causing the init function to return a negative value. As a result, Zephyr marks the device as unready:

device->state->initialized = false;

Later in the application, when calling:

device_is_ready(sht_dev)

It returns false because the initialization previously failed.

What is the recommended way to handle this situation, where a sensor is powered by the PMIC only after the boot sequence? Below, I’ve attached my .dts overlay and main.c files for reference.

.dts overlay:

#include <dt-bindings/regulator/npm1300.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>

&pinctrl {
    i2c22_default: i2c22_default {
        group1 {
            psels = <NRF_PSEL(TWIM_SDA, 1, 12)>,
                    <NRF_PSEL(TWIM_SCL, 1, 11)>;
        };
    };
    i2c22_sleep: i2c22_sleep {
        group1 {
            psels = <NRF_PSEL(TWIM_SDA, 1, 12)>,
                    <NRF_PSEL(TWIM_SCL, 1, 11)>;
            low-power-enable;
        };
    };
};

&i2c22 {
    status = "okay";
    pinctrl-0 = <&i2c22_default>;
    pinctrl-1 = <&i2c22_sleep>;
    pinctrl-names = "default", "sleep";

    
    sht4x: sht4x@44 {
        status = "okay";
        compatible = "sensirion,sht4x";
        reg = <0x44>;
        repeatability = <0>;
    };

    scd41@62 {
        compatible = "sensirion,scd41";
        reg = <0x62>;
        status = "okay";
    };


    npm1300: pmic@6b {
        compatible = "nordic,npm1300";
        reg = <0x6b>;

        npm1300_gpios: gpio-controller {
            compatible = "nordic,npm1300-gpio";
            gpio-controller;
            #gpio-cells = <2>;
            ngpios = <5>;
            status = "disabled";
        };

        npm1300_regulators: npm1300_regulators {
            compatible = "nordic,npm1300-regulator";
            status = "okay";

            npm1300_buck1: BUCK1 {
                status = "okay";
                regulator-min-microvolt = <1000000>;
                regulator-max-microvolt = <3300000>;
                regulator-init-microvolt =  <1800000>;
                retention-microvolt = <1200000>;
            };

            npm1300_buck2: BUCK2 {
                status = "okay";
                regulator-min-microvolt = <1000000>;
                regulator-max-microvolt = <3300000>;
                regulator-init-microvolt =  <3300000>;
                retention-microvolt = <1800000>;
            };

            /* Load switches */
            npm1300_ldsw1: LDO1 {
                status = "okay";
                regulator-min-microvolt = <1000000>;
                regulator-max-microvolt = <3300000>;
                regulator-initial-mode = <NPM1300_LDSW_MODE_LDSW>;
                active-discharge;
            };

            npm1300_ldsw2: LDO2 {
                status = "disabled";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                regulator-initial-mode = <NPM1300_LDSW_MODE_LDSW>;
            };
        };

        /*
        npm1300_charger: charger {
            compatible = "nordic,npm1300-charger";
            term-microvolt = <4150000>;
            current-microamp = <150000>;
            dischg-limit-microamp = <1000000>;
            vbus-limit-microamp = <500000>;
            thermistor-ohms = <10000>;
            thermistor-beta = <3380>;
            charging-enable;
            status = "okay";
        };
        */

        npm1300_leds: leds {
            compatible = "nordic,npm1300-led";
            nordic,led0-mode = "error";
            nordic,led1-mode = "charging";
            nordic,led2-mode = "host";
        };
    };
};

main.c

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/regulator.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(main_app, LOG_LEVEL_INF);

void main(void)
{
    const struct device *sht_dev = DEVICE_DT_GET(DT_NODELABEL(sht4x));
    const struct device *ldsw1 = DEVICE_DT_GET(DT_NODELABEL(npm1300_ldsw1));
    struct sensor_value temp, humidity;
   
    int ret;

    if (!device_is_ready(ldsw1)) {
        LOG_ERR("LOADSW1 device not ready");
        return;
    }

    if (!device_is_ready(sht_dev)) {
        LOG_ERR("SHT4x device not ready");
        return;
    }

    LOG_INF("Starting sensor power control via LOADSW1");

    while (1) {
        /* Turn on sensor power */
        if (!regulator_is_enabled(ldsw1))
            ret = regulator_enable(ldsw1);

        if (ret) {
            LOG_ERR("Failed to enable LOADSW1: %d", ret);
            k_sleep(K_SECONDS(10));
            continue;
        }

        LOG_INF("Sensor power ON (via LOADSW1)");

        k_sleep(K_MSEC(5)); // settle time

        ret = sensor_sample_fetch(sht_dev);
        if (!ret) {
            sensor_channel_get(sht_dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
            sensor_channel_get(sht_dev, SENSOR_CHAN_HUMIDITY, &humidity);
            LOG_INF("Temp: %d.%06d C, RH: %d.%06d%%", 
                    temp.val1, temp.val2, humidity.val1, humidity.val2);
        } else {
            LOG_ERR("Sensor read failed: %d", ret);
        }

        k_sleep(K_SECONDS(10));

        /* Power off sensor */
    
        if (regulator_is_enabled(ldsw1))
            ret = regulator_disable(ldsw1);

        if (ret) {
            LOG_ERR("Failed to disable LOADSW1: %d", ret);
            k_sleep(K_SECONDS(10));
            continue;
        }

        LOG_INF("Sensor power OFF");
        
        k_sleep(K_SECONDS(10));
    }
}

Logs output:

I spoke with the Nordic AI Assistant, and one of the suggestions was to add the property zephyr,deferred-init so that Zephyr doesn’t initialize the sensor at boot time. This allows me to manually initialize the device later using device_init(dev).

Now, my .dts overlay includes the following:

   sht4x: sht4x@44 {
        status = "okay";
        compatible = "sensirion,sht4x";
        reg = <0x44>;
        repeatability = <0>;
        zephyr,deferred-init;
    };

In main(), I added: 

  // Turn on sensor power
    if (!regulator_is_enabled(ldsw1))
        ret = regulator_enable(ldsw1);

    if (device_init(sht_dev) || !device_is_ready(sht_dev)) {
        LOG_ERR("Sensor initialization failed");
        return 0;

    }
    

The logs show that Zephyr indeed stopped trying to initialize the sensor at boot time, as expected. 

So what could be causing the issue now?

Parents Reply Children
No Data
Related