自学内容网 自学内容网

【linux】regulartor-fixed

转:https://www.cnblogs.com/ma-zhiqiang/p/17663273.html

作用:创建一个固定的 regulator。一般是一个 GPIO 控制了一路电,只有开(enable) \ 关(disabled)两种操作。

device-tree node

io_vdd_en: regulator-JW5217DFND {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&io_vdd_en_pins_default>;
gpios = <&wkup_gpio0 69 GPIO_ACTIVE_HIGH>;
regulator-name = "jw5217dfnd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
enable-active-high;
vin-supply = <&vsys_3v3>;
};

解析:

compatible

compatible = “regulator-fixed”;

固定的 regulator。特点:不能控制电压,只能 enable 和 disabled,没设备用的时候自动关电(disabled)。相关代码如下:

// drivers/regulator/fixed.c
 
static const struct regulator_ops fixed_voltage_ops = {
};
 
static const struct regulator_ops fixed_voltage_clkenabled_ops = {
.enable = reg_clock_enable,
.disable = reg_clock_disable,
.is_enabled = reg_clock_is_enabled,
};
 
static const struct of_device_id fixed_of_match[] = {
{
.compatible = "regulator-fixed",
.data = &fixed_voltage_data,
},
{
.compatible = "regulator-fixed-clock",
.data = &fixed_clkenable_data,
},
{
},
};
 
static struct platform_driver regulator_fixed_voltage_driver = {
.probe= reg_fixed_voltage_probe,
.driver= {
.name= "reg-fixed-voltage",
.of_match_table = of_match_ptr(fixed_of_match),
},
};
 
static int reg_fixed_voltage_probe(struct platform_device *pdev)
{
struct fixed_voltage_data *drvdata;
 
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
       GFP_KERNEL);
 ...
if (drvtype && drvtype->has_enable_clock) {
drvdata->desc.ops = &fixed_voltage_clkenabled_ops;
 
drvdata->enable_clock = devm_clk_get(dev, NULL);
if (IS_ERR(drvdata->enable_clock)) {
dev_err(dev, "Can't get enable-clock from devicetree\n");
return -ENOENT;
}
} else {
drvdata->desc.ops = &fixed_voltage_ops;
}
...
 
}

gpios

gpios = <&wkup_gpio0 69 GPIO_ACTIVE_HIGH>;
控制电的 GPIO。开电时(enabled)的将 GPIO 置为有效电平,关电时(disabled)置为无效电平。相关代码如下:

// drivers/regulator/fixed.c
 
static int reg_fixed_voltage_probe(struct platform_device *pdev)
{
...
cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
if (IS_ERR(cfg.ena_gpiod))
return PTR_ERR(cfg.ena_gpiod);
...
}
// drivers/regulator/core.c
 
reg_fixed_voltage_probe
  -> devm_regulator_register
    -> regulator_register
      -> regulator_ena_gpio_request
 
static int regulator_ena_gpio_request(struct regulator_dev *rdev,
const struct regulator_config *config)
{
struct regulator_enable_gpio *pin, *new_pin;
struct gpio_desc *gpiod;
 
gpiod = config->ena_gpiod;
new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL);
...
pin = new_pin;
pin->gpiod = gpiod;
rdev->ena_pin = pin;
...
}

regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator 最小及最大电压限制。对于 regulator-fixed 无实际意义。
regulator-always-on;
一直开电,防止因其他原因被关电,否则需要在其他驱动中获取此 regulator 来手动控制:regulator_enable() \ regulator_disable()。
当指定了此选项后,会有一个的虚拟设备一直在使用此 regulator,可通过如下命令查看到:

cat /sys/class/regulator/regulator.*/num_users      # 查看有多少个设备在使用此 regulator
cat /sys/class/regulator/regulator.*/state          # 查看此 regulator 的状态:enabled or disabled

regulator-boot-on;
开机时自动上电。注意:若一段时间内无设备在使用此 regulator,则会自动关电(猜测应该和系统低功耗有关),因此必须加上 regulator-always-on。

相关代码如下:

// drivers/regulator/of_regulator.c
 
reg_fixed_voltage_probe
  -> of_get_fixed_voltage_config
    -> of_get_regulator_init_data
      -> of_get_regulation_constraints
 
static int of_get_regulation_constraints(struct device *dev,
struct device_node *np,
struct regulator_init_data **init_data,
const struct regulator_desc *desc)
{
struct regulation_constraints *constraints = &(*init_data)->constraints;
 ... 
constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
constraints->always_on = of_property_read_bool(np, "regulator-always-on");
...
}
 
// drivers/regulator/core.c
 
reg_fixed_voltage_probe
  -> devm_regulator_register
    -> regulator_register
      -> set_machine_constraints
 
static int set_machine_constraints(struct regulator_dev *rdev)
{
...
if (rdev->constraints->always_on || rdev->constraints->boot_on) {
/* If we want to enable this regulator, make sure that we know
 * the supplying regulator.
 */
if (rdev->supply_name && !rdev->supply)
return -EPROBE_DEFER;
 
if (rdev->supply) {
ret = regulator_enable(rdev->supply);
if (ret < 0) {
_regulator_put(rdev->supply);
rdev->supply = NULL;
return ret;
}
}
 
ret = _regulator_do_enable(rdev);
if (ret < 0 && ret != -EINVAL) {
rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret));
return ret;
}
 
if (rdev->constraints->always_on)
rdev->use_count++;
}
...
}
// drivers/regulator/core.c
 
reg_fixed_voltage_probe
  -> devm_regulator_register
    -> regulator_register
      -> set_machine_constraints
        -> _regulator_do_enable
 
static int _regulator_do_enable(struct regulator_dev *rdev)
{
...
if (rdev->ena_pin) {
if (!rdev->ena_gpio_state) {
ret = regulator_ena_gpio_ctrl(rdev, true);
if (ret < 0)
return ret;
rdev->ena_gpio_state = 1;
}
} else if (rdev->desc->ops->enable) {
ret = rdev->desc->ops->enable(rdev);
if (ret < 0)
return ret;
} else {
return -EINVAL;
}
...
}
// drivers/regulator/core.c
 
reg_fixed_voltage_probe
  -> devm_regulator_register
    -> regulator_register
      -> set_machine_constraints
        -> _regulator_do_enable
          -> regulator_ena_gpio_ctrl
 
static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
{
struct regulator_enable_gpio *pin = rdev->ena_pin;
 
if (!pin)
return -EINVAL;
 
if (enable) {
/* Enable GPIO at initial use */
if (pin->enable_count == 0)
gpiod_set_value_cansleep(pin->gpiod, 1);
 
pin->enable_count++;
} else {
if (pin->enable_count > 1) {
pin->enable_count--;
return 0;
}
 
/* Disable GPIO if not used */
if (pin->enable_count <= 1) {
gpiod_set_value_cansleep(pin->gpiod, 0);
pin->enable_count = 0;
}
}
 
return 0;
}

自动关电的代码:

// drivers/regulator/core.c
 
regulator_init_complete_work_function
  -> regulator_late_cleanup
    -> _regulator_do_disable
      -> regulator_ena_gpio_ctrl
        -> gpiod_set_value_cansleep
 
static void regulator_init_complete_work_function(struct work_struct *work)
{
/*
 * Regulators may had failed to resolve their input supplies
 * when were registered, either because the input supply was
 * not registered yet or because its parent device was not
 * bound yet. So attempt to resolve the input supplies for
 * pending regulators before trying to disable unused ones.
 */
class_for_each_device(&regulator_class, NULL, NULL,
      regulator_register_resolve_supply);
 
/* If we have a full configuration then disable any regulators
 * we have permission to change the status for and which are
 * not in use or always_on.  This is effectively the default
 * for DT and ACPI as they have full constraints.
 */
class_for_each_device(&regulator_class, NULL, NULL,
      regulator_late_cleanup);
}
 
static DECLARE_DELAYED_WORK(regulator_init_complete_work,
    regulator_init_complete_work_function);

enable-active-high;
指定 enable GPIO 的有效电平为高(默认为低),仅适用于 regulator。在这里,GPIO 属性中的 GPIO_ACTIVE_xxx 不起作用(建议两者设置成一致,否则会有警告)。相关代码如下:

// drivers/gpio/gpiolib-of.c
 
static void of_gpio_flags_quirks(struct device_node *np,
 const char *propname,
 enum of_gpio_flags *flags,
 int index)
{
/*
 * Some GPIO fixed regulator quirks.
 * Note that active low is the default.
 */
if (IS_ENABLED(CONFIG_REGULATOR) &&
    (of_device_is_compatible(np, "regulator-fixed") ||
     of_device_is_compatible(np, "reg-fixed-voltage") ||
     (!(strcmp(propname, "enable-gpio") &&
strcmp(propname, "enable-gpios")) &&
      of_device_is_compatible(np, "regulator-gpio")))) {
bool active_low = !of_property_read_bool(np,
 "enable-active-high");
/*
 * The regulator GPIO handles are specified such that the
 * presence or absence of "enable-active-high" solely controls
 * the polarity of the GPIO line. Any phandle flags must
 * be actively ignored.
 */
if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) {
pr_warn("%s GPIO handle specifies active low - ignored\n",
of_node_full_name(np));
*flags &= ~OF_GPIO_ACTIVE_LOW;
}
if (active_low)
*flags |= OF_GPIO_ACTIVE_LOW;
}
...
}


原文地址:https://blog.csdn.net/qq_45698138/article/details/142529438

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!