Welcome to the Linux Foundation Forum!

How to defer device driver initialization?

vanovsky777
vanovsky777 Posts: 2
edited December 2022 in Kernel Development

Hello everyone
I've stuck in a problem of deferring initialization of a driver.

I need to initialize LCD panel driver after PMIC driver is done. But somehow kernel make them initialize vice versa. So, that's why I have to make special things in a driver code.

I made steps in two files:

dts:

/ {
    display-dsi {
        compatible = "simple-bus";
        #interrupt-cells = <1>;
        #address-cells = <1>;
        #size-cells = <1>;
        ranges = <>;

        lcd_eldo: reg_eldo1 {
            compatible = "regulator-fixed";
            regulator-name = "lcd_eldo";
            regulator-always-on;
            regulator-min-microvolt = <3000000>;
            regulator-max-microvolt = <3000000>;
        };

        panel_ili9881@0 {
            compatible = "ingenic,ili9881";
            power-supply = <&lcd_eldo>;
            ingenic,bl-gpio = <&gpd 2 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
            ingenic,rst-gpio = <&gpc 6 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
            ingenic,lcd_pwm-gpio = <&gpb 7 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
            status = "okay";
        };
    };
};

driver code:

static int panel_probe(struct platform_device *pdev)
{
    panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL);
    if (IS_ERR_OR_NULL(panel)) {
        dev_err(&pdev->dev, "Failed to alloc memory!\n");
        return -ENOMEM;
    }

    panel->dev = &pdev->dev;
    dev_set_drvdata(&pdev->dev, panel);

    ret = of_panel_parse(&pdev->dev);
    if (ret < 0) {
        printk("panel probe: err_of_parse\n");
        goto err_of_parse;
    }

    struct regulator * pvcc;
    pvcc = devm_regulator_get(&pdev->dev, "lcd_eldo"); 
    if (IS_ERR(pvcc)) {
        printk("---##&##--- lcd_eldo LCD: FAIL\n");
        return -EPROBE_DEFER;
    }
    /* ... */
}

I expected the project work normally, but a system log shows following:

display-dsi:panel_ili9881@0 supply lcd_eldo not found, using dummy regulator

As far as I understand it means:

  • devm_regulator_get() can not find regulator name
  • system should have returned an error, but it activates the dummy_regulator instead

Any ideas?

Best Answer

  • vanovsky777
    vanovsky777 Posts: 2
    edited December 2022 Answer ✓

    I've found a solution I guess
    I should have used a devm_regulator_get_exclusive() function, because it does not activates dummy_regulator and returns an error instead. Then it becomes possible to operate the returning value to defer the driver initialization.

    The function body:

    struct regulator *devm_regulator_get_exclusive(struct device *dev, char *id)
    {
        return _devm_regulator_get(dev, id, EXCLUSIVE_GET);
    }
    

    Then in the function the system goes to case EXCLUSIVE_GET

    static struct regulator *_devm_regulator_get(struct device *dev, const char *id, get_type)
    {
        struct regulator **ptr, *regulator;
        ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
        if (!ptr)
            return ERR_PTR(-ENOMEM);
    
        switch (get_type) {
        case NORMAL_GET:
            regulator = regulator_get(dev, id); break;
        case EXCLUSIVE_GET:
            regulator = regulator_get_exclusive(dev, id); break;
        case OPTIONAL_GET:
            regulator = regulator_get_optional(dev, id); break;
        default:
            regulator = ERR_PTR(-EINVAL);
        }
    
        if (!IS_ERR(regulator)) {
            *ptr = regulator;
            devres_add(dev, ptr);
        } else
            devres_free(ptr);
    
        return regulator;
    }
    

    Then

    struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
    {
        return _regulator_get(dev, id, true, false);
    }
    
    /* _regulator_get heading */
    static struct regulator *_regulator_get (
        struct device *dev, 
        const char *id, 
        bool exclusive, 
        bool allow_dummy
    )
    /*
     * allow_dummy = false
     */
    

    That means the devm_regulator_get_exclusive() function returns what I need

        struct regulator * pvcc;
        pvcc = devm_regulator_get_exclusive(&pdev->dev, "lcd_eldo"); 
        if (IS_ERR(pvcc)) {
            printk("---##&##--- lcd_eldo LCD: FAIL\n");
            return -EPROBE_DEFER;
        }
        /* ... */
    

    It works normally:

    • accroding to the error code of devm_regulator_get_exclusive() I can return EPROBE_DEFER in driver probe function
    • if there is no error code, it's possible to make my driver initialize

Answers

  • brain011
    brain011 Posts: 1
    edited February 2023

    @vanovsky777 said:
    I've found a solution I guess
    I should have used a devm_regulator_get_exclusive() function, because it does not activates dummy_regulator and returns an error instead. Then it becomes possible to operate the returning value to defer the driver initialization.

    The function body:

    struct regulator *devm_regulator_get_exclusive(struct device *dev, char *id)
    {
      return _devm_regulator_get(dev, id, EXCLUSIVE_GET);
    }
    

    Then in the function the system goes to case EXCLUSIVE_GET

    static struct regulator *_devm_regulator_get(struct device *dev, const char *id, get_type)
    {
      struct regulator **ptr, *regulator;
      ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
      if (!ptr)
          return ERR_PTR(-ENOMEM);
    
      switch (get_type) {
      case NORMAL_GET:
          regulator = regulator_get(dev, id); break;
      case EXCLUSIVE_GET:
          regulator = regulator_get_exclusive(dev, id); break;
      case OPTIONAL_GET:
          regulator = regulator_get_optional(dev, id); break;
      default:
          regulator = ERR_PTR(-EINVAL);
      }
    
      if (!IS_ERR(regulator)) {
          *ptr = regulator;
          devres_add(dev, ptr);
      } else
          devres_free(ptr);
    
      return regulator;
    }
    

    Then

    struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
    {
      return _regulator_get(dev, it, true, false);
    }
    
    /* _regulator_get heading */
    static struct regulator *_regulator_get (
      struct device *dev, 
      const char *id, 
      bool exclusive, 
      bool allow_dummy
    )
    /*
     * allow_dummy = false
     */
    

    That means the devm_regulator_get_exclusive() function returns what I need

        struct regulator * pvcc;
        pvcc = devm_regulator_get_exclusive(&pdev->dev, "lcd_eldo"); 
        if (IS_ERR(pvcc)) {
            printk("---##&##--- lcd_eldo LCD: FAIL\n");
            return -EPROBE_DEFER;
        }
        /* ... */
    

    It works normally:

    • accroding to the error code of devm_regulator_get_exclusive() I can return EPROBE_DEFER in driver probe function
    • if there is no error code, it's possible to make my driver initialize

    Exactly, this is the best answer to the problem "How to defer device driver initialization?. Thanks to vanovsky777
    vanovsky777.

Categories

Upcoming Training