Regulator fixed is broken in nrf sdk 3.2.1

After upgrading nRF Connect SDK from 3.1.1 to 3.2.1, our fixed regulator stopped working. We are on nRF54L15. Tracking it down further, this seems to be some sort of GPIO value config/retention bug. The reason I'm saying "bug" is that this was working as expected on 3.1.1. Our regulator is defined in the dts to go high on boot.

load_3v3: load-3v3 {
  compatible = "regulator-fixed";
  status = "okay";
  regulator-name = "3V3_LOAD_EN";
  enable-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
  regulator-boot-on;
};

If you look at regulator_fixed_init() in the latest SDK, it configures the output pin, then reads the value. That value is passed regulator_common_init(), which only toggles the line high if it's not already `is_enabled`. However, for some reason, the gpio read of the pin reads HIGH immediately after config. This causes regulator_common_init() to think it's already on, when it's not actually on. If I add a 10ms delay and read the same value again, it correctly reads 0. In the logs below, the reading of value after sleep doesn't change is_enabled because that was added by me, is_enabled is still based on the value after the first read like in the unmodified code.

[00:00:00.323,296] <wrn> regulator_fixed: Regulator before config: 0
[00:00:00.323,296] <wrn> regulator_fixed: Regulator after config 1
[00:00:00.323,296] <wrn> regulator_fixed: Sleeping for 10ms
[00:00:00.333,408] <wrn> regulator_fixed: Regulator after 10ms sleep: 0
[00:00:00.333,408] <wrn> regulator_fixed: Calling regulator_common_init with is_enabled=1

Why does gpio_pin_get_dt() return 1 temporarily? This breaks the regulator setup.

Instrumented regulator_fixed_init with logs, but otherwise unchanged:

static int regulator_fixed_init(const struct device *dev)
{
  const struct regulator_fixed_config *cfg = dev->config;
  bool is_enabled = false;

  regulator_common_data_init(dev);

  if (cfg->enable.port != NULL) {
    if (!gpio_is_ready_dt(&cfg->enable)) {
     LOG_ERR("GPIO port: %s not ready", cfg->enable.port->name);
     return -ENODEV;
    }

    // DEBUG CODE
    LOG_WRN("Regulator before config: %d", gpio_pin_get_dt(&cfg->enable));
    // END DEBUG CODE

    int ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT);

    if (ret < 0) {
       return ret;
    }

    ret = gpio_pin_get_dt(&cfg->enable);

    if (ret < 0) {
      return ret;
    }

    is_enabled = ret;

    // DEBUG CODE
    LOG_WRN("Regulator after config %d", is_enabled);
    LOG_WRN("Sleeping for 10ms");

    k_sleep(K_MSEC(10));

    LOG_WRN("Regulator after 10ms sleep: %d", gpio_pin_get_dt(&cfg->enable));
    // END DEBUG CODE
  }

  LOG_WRN("Calling regulator_common_init with is_enabled=%d", is_enabled);
  return regulator_common_init(dev, is_enabled);
}

This issue has surfaced because of this commit in zephyr: https://github.com/nrfconnect/sdk-zephyr/commit/7fa815c92967f26a7c9af33776677015013e18d0, which checks the value of the pin before deciding if it should be toggled.

Parents
  • Hello,

    I did not have any luck replicating the issue. In my case it is always being read as '0' as you can see from the screen dump below. This was tested on a nRF54L15 DK with SDK v3.2.1.  

    I also find it strange that we are trying to read the GPIO input right after we have configured it as an output. The gpio_pin_get_dt() will read the GPIO.IN register which is only valid when the pin is configured as an input. Perhaps it works differently on other platforms. 

    Attached is the sample I used for test, perhaps you could have a look at it to see if we are doing anything differently?

    Best regards,

    Vidar

    regulator_fixed_test.zip

  • Thanks, I see the same thing. Both your example and our project behave fine on the nrf54l15 dk. This may be some sort of hardware issue on our end. But to your point, what's in the GPIO.IN if the pin is set to output? How/why could it read 1 after configuring it as an output? Is it possible there's some pull up or capacitance? Anything happens on the GPIO during config?

    If you agree that zephyr's driver is incorrect, even if it seems to result in correct behavior on the dk, what/how should that be addressed?

    Update: after speaking with our HW eng, we identified that the pull-up and decoupling cap on that regulator line were causing this issue. It seems that configuring the pin as the output briefly pulls up the line and GPIO.IN reads 1 for a few milliseconds. When we removed the pull-up and the capacitor, that issue went away. It seems that even if the pin is not set to input, the GPIO.IN register does do something.

    So the takeway is that if any customers are using fixed regulator with a pull-up/decoupling cap config, they can not use current zephyr regulator driver. Is that accurate?

  • Actually, after supplying VDD to the GPIO pad, I’m also reading ‘1’ in the regulator init function. I was certain that it was not possible to read the logic level from an output, but since it appears to be possible, could there be that there is voltage on this line that needs some time to discharge before it goes low? Do you see the same if you do a full power cycle of the board? Either way, I will discuss the case with my coworkers as well to see if I may be missing something. 

Reply
  • Actually, after supplying VDD to the GPIO pad, I’m also reading ‘1’ in the regulator init function. I was certain that it was not possible to read the logic level from an output, but since it appears to be possible, could there be that there is voltage on this line that needs some time to discharge before it goes low? Do you see the same if you do a full power cycle of the board? Either way, I will discuss the case with my coworkers as well to see if I may be missing something. 

Children
Related