[dm][regulator] Update Regulator (#11674)

* [dm][regulator] update regulator

Replace the regulator framework spinlock with a mutex
because regulator operations may sleep.
Move always-on policy into the regulator core,
keep an initial enable reference for always-on supplies,
prevent the last disable from turning them off,
and let fixed/GPIO providers report and control their actual hardware state.

Signed-off-by: GuEe-GUI <2991707448@qq.com>

* [dm][regulator] add PWM regulator support

Signed-off-by: GuEe-GUI <2991707448@qq.com>

* style: format code with clang-format

* style: format complete changed files with clang-format

---------

Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
GUI 2026-08-07 21:29:33 +08:00 committed by GitHub
parent 19e9be8779
commit c19fe2c823
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 799 additions and 148 deletions

View File

@ -2,12 +2,12 @@ menuconfig RT_USING_REGULATOR
bool "Using Voltage and Current Regulator"
select RT_USING_ADT
select RT_USING_ADT_REF
default n
config RT_REGULATOR_FAN53555
bool "Fairchild FAN53555 / TCS4525 Regulator"
depends on RT_USING_REGULATOR
depends on RT_USING_I2C
depends on RT_USING_DM
default n
config RT_REGULATOR_FIXED
@ -27,6 +27,15 @@ config RT_REGULATOR_GPIO
depends on RT_USING_PIN
default y
config RT_REGULATOR_PWM
bool "PWM regulator support"
depends on RT_USING_REGULATOR
depends on RT_USING_DM
depends on RT_USING_PWM
depends on RT_USING_PIN
depends on RT_USING_OFW
default n
config RT_REGULATOR_SCMI
bool "SCMI regulator support"
depends on RT_USING_REGULATOR

View File

@ -19,6 +19,9 @@ if GetDepend(['RT_REGULATOR_FIXED']):
if GetDepend(['RT_REGULATOR_GPIO']):
src += ['regulator-gpio.c']
if GetDepend(['RT_REGULATOR_PWM']):
src += ['regulator-pwm.c']
if GetDepend(['RT_REGULATOR_SCMI']):
src += ['regulator-scmi.c']

View File

@ -12,10 +12,10 @@
struct regulator_fixed
{
struct rt_regulator_node parent;
struct rt_regulator_node parent;
struct rt_regulator_param param;
rt_base_t enable_pin;
rt_base_t enable_pin;
const char *input_supply;
};
@ -23,10 +23,10 @@ struct regulator_fixed
static rt_err_t regulator_fixed_enable(struct rt_regulator_node *reg_np)
{
struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np);
struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np);
struct rt_regulator_param *param = &rf->param;
if (rf->enable_pin < 0 || param->always_on)
if (rf->enable_pin < 0)
{
return RT_EOK;
}
@ -39,32 +39,31 @@ static rt_err_t regulator_fixed_enable(struct rt_regulator_node *reg_np)
static rt_err_t regulator_fixed_disable(struct rt_regulator_node *reg_np)
{
struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np);
struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np);
struct rt_regulator_param *param = &rf->param;
if (rf->enable_pin < 0 || param->always_on)
if (rf->enable_pin < 0)
{
return RT_EOK;
}
rt_pin_mode(rf->enable_pin, PIN_MODE_OUTPUT);
rt_pin_write(rf->enable_pin, param->enable_active_high ? PIN_LOW: PIN_HIGH);
rt_pin_write(rf->enable_pin, param->enable_active_high ? PIN_LOW : PIN_HIGH);
return RT_EOK;
}
static rt_bool_t regulator_fixed_is_enabled(struct rt_regulator_node *reg_np)
{
rt_uint8_t active;
struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np);
rt_uint8_t active;
struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np);
struct rt_regulator_param *param = &rf->param;
if (rf->enable_pin < 0 || param->always_on)
if (rf->enable_pin < 0)
{
return RT_TRUE;
}
rt_pin_mode(rf->enable_pin, PIN_MODE_INPUT);
active = rt_pin_read(rf->enable_pin);
if (param->enable_active_high)
@ -82,20 +81,19 @@ static int regulator_fixed_get_voltage(struct rt_regulator_node *reg_np)
return rf->param.min_uvolt + (rf->param.max_uvolt - rf->param.min_uvolt) / 2;
}
static const struct rt_regulator_ops regulator_fixed_ops =
{
.enable = regulator_fixed_enable,
.disable = regulator_fixed_disable,
.is_enabled = regulator_fixed_is_enabled,
static const struct rt_regulator_ops regulator_fixed_ops = {
.enable = regulator_fixed_enable,
.disable = regulator_fixed_disable,
.is_enabled = regulator_fixed_is_enabled,
.get_voltage = regulator_fixed_get_voltage,
};
static rt_err_t regulator_fixed_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
rt_uint32_t val;
struct rt_device *dev = &pdev->parent;
struct regulator_fixed *rf = rt_calloc(1, sizeof(*rf));
rt_err_t err;
rt_uint32_t val;
struct rt_device *dev = &pdev->parent;
struct regulator_fixed *rf = rt_calloc(1, sizeof(*rf));
struct rt_regulator_node *rnp;
if (!rf)
@ -105,11 +103,11 @@ static rt_err_t regulator_fixed_probe(struct rt_platform_device *pdev)
regulator_ofw_parse(dev->ofw_node, &rf->param);
rnp = &rf->parent;
rnp = &rf->parent;
rnp->supply_name = rf->param.name;
rnp->ops = &regulator_fixed_ops;
rnp->param = &rf->param;
rnp->dev = &pdev->parent;
rnp->ops = &regulator_fixed_ops;
rnp->param = &rf->param;
rnp->dev = &pdev->parent;
rf->enable_pin = rt_pin_get_named_pin(dev, "enable", 0, RT_NULL, RT_NULL);
@ -148,16 +146,14 @@ _fail:
return err;
}
static const struct rt_ofw_node_id regulator_fixed_ofw_ids[] =
{
static const struct rt_ofw_node_id regulator_fixed_ofw_ids[] = {
{ .compatible = "regulator-fixed" },
{ /* sentinel */ }
};
static struct rt_platform_driver regulator_fixed_driver =
{
static struct rt_platform_driver regulator_fixed_driver = {
.name = "reg-fixed-voltage",
.ids = regulator_fixed_ofw_ids,
.ids = regulator_fixed_ofw_ids,
.probe = regulator_fixed_probe,
};

View File

@ -20,7 +20,7 @@ struct regulator_gpio_state
struct regulator_gpio_desc
{
rt_base_t pin;
rt_base_t pin;
rt_uint32_t flags;
};
@ -30,17 +30,17 @@ struct regulator_gpio
rt_base_t enable_pin;
rt_size_t pins_nr;
rt_size_t pins_nr;
struct regulator_gpio_desc *pins_desc;
int state;
rt_size_t states_nr;
int state;
rt_size_t states_nr;
struct regulator_gpio_state *states;
const char *input_supply;
rt_uint32_t startup_delay;
rt_uint32_t off_on_delay;
rt_bool_t enabled_at_boot;
const char *input_supply;
rt_uint32_t startup_delay;
rt_uint32_t off_on_delay;
rt_bool_t enabled_at_boot;
struct rt_regulator_param param;
};
@ -48,14 +48,9 @@ struct regulator_gpio
static rt_err_t regulator_gpio_enable(struct rt_regulator_node *reg_np)
{
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
struct rt_regulator_param *param = &rg->param;
if (param->always_on)
{
return RT_EOK;
}
if (rg->enable_pin >= 0)
{
rt_pin_mode(rg->enable_pin, PIN_MODE_OUTPUT);
@ -67,14 +62,9 @@ static rt_err_t regulator_gpio_enable(struct rt_regulator_node *reg_np)
static rt_err_t regulator_gpio_disable(struct rt_regulator_node *reg_np)
{
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
struct rt_regulator_param *param = &rg->param;
if (param->always_on)
{
return RT_EOK;
}
if (rg->enable_pin >= 0)
{
rt_pin_mode(rg->enable_pin, PIN_MODE_OUTPUT);
@ -86,14 +76,9 @@ static rt_err_t regulator_gpio_disable(struct rt_regulator_node *reg_np)
static rt_bool_t regulator_gpio_is_enabled(struct rt_regulator_node *reg_np)
{
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
struct rt_regulator_param *param = &rg->param;
if (param->always_on)
{
return RT_TRUE;
}
if (rg->enable_pin >= 0)
{
rt_uint8_t active_val = param->enable_active_high ? PIN_LOW : PIN_HIGH;
@ -106,9 +91,9 @@ static rt_bool_t regulator_gpio_is_enabled(struct rt_regulator_node *reg_np)
}
static rt_err_t regulator_gpio_set_voltage(struct rt_regulator_node *reg_np,
int min_uvolt, int max_uvolt)
int min_uvolt, int max_uvolt)
{
int target = 0, best_val = RT_REGULATOR_UVOLT_INVALID;
int target = 0, best_val = RT_REGULATOR_UVOLT_INVALID;
struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np);
for (int i = 0; i < rg->states_nr; ++i)
@ -119,7 +104,7 @@ static rt_err_t regulator_gpio_set_voltage(struct rt_regulator_node *reg_np,
state->value >= min_uvolt &&
state->value <= max_uvolt)
{
target = state->gpios;
target = state->gpios;
best_val = state->value;
}
}
@ -131,7 +116,7 @@ static rt_err_t regulator_gpio_set_voltage(struct rt_regulator_node *reg_np,
for (int i = 0; i < rg->pins_nr; ++i)
{
int state = (target >> i) & 1;
int state = (target >> i) & 1;
struct regulator_gpio_desc *gpiod = &rg->pins_desc[i];
rt_pin_mode(gpiod->pin, PIN_MODE_OUTPUT);
@ -158,20 +143,19 @@ static int regulator_gpio_get_voltage(struct rt_regulator_node *reg_np)
return -RT_EINVAL;
}
static const struct rt_regulator_ops regulator_gpio_ops =
{
.enable = regulator_gpio_enable,
.disable = regulator_gpio_disable,
.is_enabled = regulator_gpio_is_enabled,
static const struct rt_regulator_ops regulator_gpio_ops = {
.enable = regulator_gpio_enable,
.disable = regulator_gpio_disable,
.is_enabled = regulator_gpio_is_enabled,
.set_voltage = regulator_gpio_set_voltage,
.get_voltage = regulator_gpio_get_voltage,
};
static rt_err_t regulator_gpio_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
struct rt_device *dev = &pdev->parent;
struct regulator_gpio *rg = rt_calloc(1, sizeof(*rg));
rt_err_t err;
struct rt_device *dev = &pdev->parent;
struct regulator_gpio *rg = rt_calloc(1, sizeof(*rg));
struct rt_regulator_node *rgp;
if (!rg)
@ -181,11 +165,11 @@ static rt_err_t regulator_gpio_probe(struct rt_platform_device *pdev)
regulator_ofw_parse(dev->ofw_node, &rg->param);
rgp = &rg->parent;
rgp = &rg->parent;
rgp->supply_name = rg->param.name;
rgp->ops = &regulator_gpio_ops;
rgp->param = &rg->param;
rgp->dev = &pdev->parent;
rgp->ops = &regulator_gpio_ops;
rgp->param = &rg->param;
rgp->dev = &pdev->parent;
rt_dm_dev_prop_read_u32(dev, "startup-delay-us", &rg->startup_delay);
rt_dm_dev_prop_read_u32(dev, "off-on-delay-us", &rg->off_on_delay);
@ -214,7 +198,7 @@ static rt_err_t regulator_gpio_probe(struct rt_platform_device *pdev)
for (int i = 0; i < rg->pins_nr; ++i)
{
rt_uint32_t val;
rt_uint32_t val;
struct regulator_gpio_desc *gpiod = &rg->pins_desc[i];
gpiod->pin = rt_pin_get_named_pin(dev, RT_NULL, i, RT_NULL, RT_NULL);
@ -286,16 +270,14 @@ _fail:
return err;
}
static const struct rt_ofw_node_id regulator_gpio_ofw_ids[] =
{
static const struct rt_ofw_node_id regulator_gpio_ofw_ids[] = {
{ .compatible = "regulator-gpio" },
{ /* sentinel */ }
};
static struct rt_platform_driver regulator_gpio_driver =
{
static struct rt_platform_driver regulator_gpio_driver = {
.name = "regulator-gpio",
.ids = regulator_gpio_ofw_ids,
.ids = regulator_gpio_ofw_ids,
.probe = regulator_gpio_probe,
};

View File

@ -0,0 +1,617 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-26 GuEe-GUI first version
*/
#define DBG_TAG "regulator.pwm"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include "regulator_dm.h"
struct pwm_continuous_reg_data
{
rt_uint32_t min_uvolt_dutycycle;
rt_uint32_t max_uvolt_dutycycle;
rt_uint32_t dutycycle_unit;
};
struct pwm_voltages
{
rt_uint32_t uvolt;
rt_uint32_t dutycycle;
};
struct pwm_regulator
{
struct rt_regulator_node parent;
struct rt_regulator_param param;
rt_bool_t enabled;
rt_uint8_t enable_active_value;
struct rt_device_pwm *pwm_dev;
struct rt_pwm_configuration pwm_conf;
struct pwm_voltages *duty_cycle_table;
struct pwm_continuous_reg_data continuous;
int init_uvolt;
int selector;
rt_uint32_t n_voltages;
rt_base_t enable_pin;
};
#define raw_to_pwm_regulator(raw) rt_container_of(raw, struct pwm_regulator, parent)
static rt_uint8_t pwm_regulator_enable_pin_value(struct pwm_regulator *pr, rt_bool_t enable)
{
return enable ? pr->enable_active_value : !pr->enable_active_value;
}
static rt_err_t pwm_regulator_get_config(struct pwm_regulator *pr,
struct rt_pwm_configuration *pwm_conf)
{
rt_memset(pwm_conf, 0, sizeof(*pwm_conf));
pwm_conf->channel = pr->pwm_conf.channel;
return rt_pwm_get(pr->pwm_dev, pwm_conf);
}
static rt_err_t pwm_regulator_apply_config(struct pwm_regulator *pr,
struct rt_pwm_configuration *pwm_conf)
{
rt_err_t err;
if (!pwm_conf->period || pwm_conf->pulse > pwm_conf->period)
{
return -RT_EINVAL;
}
pwm_conf->channel = pr->pwm_conf.channel;
/*
* rt_pwm_set() only passes period and pulse, so use the complete
* configuration to retain the polarity from the PWM DT specifier.
*/
err = rt_device_control(&pr->pwm_dev->parent, PWM_CMD_SET, pwm_conf);
if (!err)
{
pr->pwm_conf = *pwm_conf;
}
return err;
}
static rt_err_t pwm_regulator_adjust_config(struct pwm_regulator *pr)
{
rt_err_t err;
struct rt_pwm_configuration current;
struct rt_pwm_configuration adjusted = pr->pwm_conf;
if ((err = pwm_regulator_get_config(pr, &current)))
{
return err;
}
if (!current.period)
{
adjusted.pulse = 0;
}
else
{
if (current.pulse > current.period)
{
current.pulse = current.period;
}
adjusted.pulse = RT_DIV_ROUND_CLOSEST_ULL(
(rt_uint64_t)current.pulse * adjusted.period,
current.period);
if (current.complementary != adjusted.complementary)
{
adjusted.pulse = adjusted.period - adjusted.pulse;
}
}
return pwm_regulator_apply_config(pr, &adjusted);
}
static rt_err_t pwm_regulator_init_state(struct pwm_regulator *pr)
{
rt_err_t err;
rt_uint32_t dutycycle;
struct rt_pwm_configuration pwm_conf;
if ((err = pwm_regulator_get_config(pr, &pwm_conf)))
{
return err;
}
dutycycle = pwm_conf.period ? RT_DIV_ROUND_CLOSEST_ULL(
(rt_uint64_t)pwm_conf.pulse * 100, pwm_conf.period)
: 0;
for (int i = 0; i < pr->n_voltages; ++i)
{
if (dutycycle == pr->duty_cycle_table[i].dutycycle)
{
pr->selector = i;
return RT_EOK;
}
}
return -RT_EINVAL;
}
static rt_err_t pwm_regulator_enable(struct rt_regulator_node *reg_np)
{
rt_err_t err;
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
if (pr->init_uvolt)
{
struct rt_pwm_configuration pwm_conf;
if ((err = pwm_regulator_get_config(pr, &pwm_conf)))
{
return err;
}
if (!pwm_conf.pulse &&
(err = reg_np->ops->set_voltage(reg_np,
pr->init_uvolt, pr->init_uvolt)))
{
return err;
}
}
if (pr->enable_pin >= 0)
{
rt_pin_mode(pr->enable_pin, PIN_MODE_OUTPUT);
rt_pin_write(pr->enable_pin, pwm_regulator_enable_pin_value(pr, RT_TRUE));
}
if (!(err = rt_pwm_enable(pr->pwm_dev, pr->pwm_conf.channel)))
{
pr->enabled = RT_TRUE;
}
else if (pr->enable_pin >= 0)
{
rt_pin_write(pr->enable_pin, pwm_regulator_enable_pin_value(pr, RT_FALSE));
}
return err;
}
static rt_err_t pwm_regulator_disable(struct rt_regulator_node *reg_np)
{
rt_err_t err;
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
if ((err = rt_pwm_disable(pr->pwm_dev, pr->pwm_conf.channel)))
{
return err;
}
pr->enabled = RT_FALSE;
if (pr->enable_pin >= 0)
{
rt_pin_mode(pr->enable_pin, PIN_MODE_OUTPUT);
rt_pin_write(pr->enable_pin, pwm_regulator_enable_pin_value(pr, RT_FALSE));
}
return RT_EOK;
}
static rt_bool_t pwm_regulator_is_enabled(struct rt_regulator_node *reg_np)
{
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
if (pr->enable_pin >= 0)
{
if (rt_pin_read(pr->enable_pin) != pr->enable_active_value)
{
return RT_FALSE;
}
}
return pr->enabled;
}
static rt_err_t pwm_regulator_table_set_voltage(struct rt_regulator_node *reg_np,
int min_uvolt, int max_uvolt)
{
rt_err_t err;
int selector = -1;
rt_uint32_t duty_cycle;
struct rt_pwm_configuration pwm_conf = {};
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
for (int i = 0; i < pr->n_voltages; ++i)
{
int uvolt = pr->duty_cycle_table[i].uvolt;
if (uvolt >= min_uvolt && uvolt <= max_uvolt &&
(selector < 0 || uvolt < pr->duty_cycle_table[selector].uvolt))
{
selector = i;
}
}
if (selector < 0)
{
return -RT_EINVAL;
}
pwm_conf = pr->pwm_conf;
duty_cycle = pr->duty_cycle_table[selector].dutycycle;
duty_cycle = RT_DIV_ROUND_CLOSEST_ULL((rt_uint64_t)duty_cycle * pwm_conf.period, 100);
pwm_conf.pulse = duty_cycle;
if ((err = pwm_regulator_apply_config(pr, &pwm_conf)))
{
return err;
}
pr->selector = selector;
return RT_EOK;
}
static int pwm_regulator_table_get_voltage(struct rt_regulator_node *reg_np)
{
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
if (pr->selector < 0)
{
if (pwm_regulator_init_state(pr))
{
return RT_REGULATOR_UVOLT_INVALID;
}
}
return pr->duty_cycle_table[pr->selector].uvolt;
}
static rt_err_t pwm_regulator_continuous_set_voltage(struct rt_regulator_node *reg_np,
int min_uvolt, int max_uvolt)
{
rt_err_t err;
int target_uvolt;
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
struct rt_pwm_configuration pwm_conf = pr->pwm_conf;
rt_uint32_t min_uvolt_duty = pr->continuous.min_uvolt_dutycycle;
rt_uint32_t max_uvolt_duty = pr->continuous.max_uvolt_dutycycle;
rt_uint32_t duty_unit = pr->continuous.dutycycle_unit, diff_duty, dutycycle;
int fix_min_uvolt = reg_np->param->min_uvolt;
int fix_max_uvolt = reg_np->param->max_uvolt;
int diff_uvolt = fix_max_uvolt - fix_min_uvolt;
target_uvolt = min_uvolt < fix_min_uvolt ? fix_min_uvolt : min_uvolt;
if (min_uvolt > max_uvolt || target_uvolt > max_uvolt ||
target_uvolt > fix_max_uvolt || diff_uvolt <= 0)
{
return -RT_EINVAL;
}
if (max_uvolt_duty < min_uvolt_duty)
{
diff_duty = min_uvolt_duty - max_uvolt_duty;
}
else
{
diff_duty = max_uvolt_duty - min_uvolt_duty;
}
dutycycle = RT_DIV_ROUND_CLOSEST_ULL(
(rt_uint64_t)(target_uvolt - fix_min_uvolt) * diff_duty, diff_uvolt);
if (max_uvolt_duty < min_uvolt_duty)
{
dutycycle = min_uvolt_duty - dutycycle;
}
else
{
dutycycle = min_uvolt_duty + dutycycle;
}
pwm_conf.pulse = RT_DIV_ROUND_CLOSEST_ULL(
(rt_uint64_t)dutycycle * pwm_conf.period, duty_unit);
err = pwm_regulator_apply_config(pr, &pwm_conf);
return err;
}
static int pwm_regulator_continuous_get_voltage(struct rt_regulator_node *reg_np)
{
rt_err_t err;
struct pwm_regulator *pr = raw_to_pwm_regulator(reg_np);
struct rt_pwm_configuration pwm_conf;
rt_uint32_t min_uvolt_duty = pr->continuous.min_uvolt_dutycycle;
rt_uint32_t max_uvolt_duty = pr->continuous.max_uvolt_dutycycle;
rt_uint32_t duty_unit = pr->continuous.dutycycle_unit, diff_duty;
rt_uint32_t min_duty, max_duty;
int min_uvolt = reg_np->param->min_uvolt;
int max_uvolt = reg_np->param->max_uvolt;
int uvolt, diff_uvolt = max_uvolt - min_uvolt;
if ((err = pwm_regulator_get_config(pr, &pwm_conf)))
{
return err;
}
uvolt = pwm_conf.period ? RT_DIV_ROUND_CLOSEST_ULL(
(rt_uint64_t)pwm_conf.pulse * duty_unit,
pwm_conf.period)
: 0;
min_duty = min_uvolt_duty < max_uvolt_duty ? min_uvolt_duty : max_uvolt_duty;
max_duty = min_uvolt_duty > max_uvolt_duty ? min_uvolt_duty : max_uvolt_duty;
if (uvolt < min_duty || uvolt > max_duty)
{
return RT_REGULATOR_UVOLT_INVALID;
}
if (max_uvolt_duty < min_uvolt_duty)
{
uvolt = min_uvolt_duty - uvolt;
diff_duty = min_uvolt_duty - max_uvolt_duty;
}
else
{
uvolt = uvolt - min_uvolt_duty;
diff_duty = max_uvolt_duty - min_uvolt_duty;
}
uvolt = RT_DIV_ROUND_CLOSEST_ULL((rt_uint64_t)uvolt * diff_uvolt, diff_duty);
return uvolt + min_uvolt;
}
static const struct rt_regulator_ops pwm_regulator_voltage_table_ops = {
.enable = pwm_regulator_enable,
.disable = pwm_regulator_disable,
.is_enabled = pwm_regulator_is_enabled,
.set_voltage = pwm_regulator_table_set_voltage,
.get_voltage = pwm_regulator_table_get_voltage,
};
static const struct rt_regulator_ops pwm_regulator_voltage_continuous_ops = {
.enable = pwm_regulator_enable,
.disable = pwm_regulator_disable,
.is_enabled = pwm_regulator_is_enabled,
.set_voltage = pwm_regulator_continuous_set_voltage,
.get_voltage = pwm_regulator_continuous_get_voltage,
};
static rt_err_t pwm_regulator_init_table(struct rt_ofw_node *np,
struct pwm_regulator *pr)
{
rt_err_t err;
rt_ssize_t length = 0;
struct pwm_voltages *duty_cycle_table;
rt_ofw_prop_read_raw(np, "voltage-table", &length);
if ((length < sizeof(*duty_cycle_table)) ||
(length % sizeof(*duty_cycle_table)))
{
LOG_E("`voltage-table` length = %d is invalid", length);
return -RT_EINVAL;
}
duty_cycle_table = rt_calloc(1, length);
if (!duty_cycle_table)
{
return -RT_ENOMEM;
}
err = rt_ofw_prop_read_u32_array_index(np, "voltage-table",
0, length / sizeof(rt_uint32_t), (rt_uint32_t *)duty_cycle_table);
if (err < 0)
{
rt_free(duty_cycle_table);
return err;
}
for (int i = 0; i < length / sizeof(*duty_cycle_table); ++i)
{
if (duty_cycle_table[i].dutycycle > 100)
{
rt_free(duty_cycle_table);
return -RT_EINVAL;
}
}
pr->duty_cycle_table = duty_cycle_table;
pr->selector = -1;
pr->n_voltages = length / sizeof(*duty_cycle_table);
pr->parent.ops = &pwm_regulator_voltage_table_ops;
return RT_EOK;
}
static rt_err_t pwm_regulator_init_continuous(struct rt_ofw_node *np,
struct pwm_regulator *pr)
{
rt_uint32_t dutycycle_unit = 100, dutycycle_range[2] = { 0, 100 };
rt_ofw_prop_read_u32_array_index(np, "pwm-dutycycle-range", 0, 2,
dutycycle_range);
rt_ofw_prop_read_u32(np, "pwm-dutycycle-unit", &dutycycle_unit);
if (!dutycycle_unit ||
dutycycle_range[0] > dutycycle_unit ||
dutycycle_range[1] > dutycycle_unit ||
dutycycle_range[0] == dutycycle_range[1] ||
pr->param.min_uvolt >= pr->param.max_uvolt)
{
return -RT_EINVAL;
}
pr->continuous.dutycycle_unit = dutycycle_unit;
pr->continuous.min_uvolt_dutycycle = dutycycle_range[0];
pr->continuous.max_uvolt_dutycycle = dutycycle_range[1];
pr->parent.ops = &pwm_regulator_voltage_continuous_ops;
return RT_EOK;
}
static rt_err_t pwm_regulator_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
struct rt_ofw_cell_args pwm_args;
struct rt_ofw_node *np = pdev->parent.ofw_node, *pwm_np;
struct pwm_regulator *pr = rt_calloc(1, sizeof(*pr));
struct rt_regulator_node *rgp;
if (!pr)
{
return -RT_ENOMEM;
}
if ((err = regulator_ofw_parse(np, &pr->param)))
{
goto _fail;
}
if (rt_ofw_parse_phandle_cells(np, "pwms", "#pwm-cells", 0, &pwm_args))
{
err = -RT_EINVAL;
goto _fail;
}
if (pwm_args.args_count < 2 || !pwm_args.args[1])
{
rt_ofw_node_put(pwm_args.data);
err = -RT_EINVAL;
goto _fail;
}
pwm_np = pwm_args.data;
if (!rt_ofw_data(pwm_np))
{
rt_platform_ofw_request(pwm_np);
}
pr->pwm_dev = rt_ofw_data(pwm_np);
rt_ofw_node_put(pwm_np);
if (!pr->pwm_dev)
{
err = -RT_EINVAL;
goto _fail;
}
pr->pwm_conf.channel = pwm_args.args[0];
pr->pwm_conf.period = pwm_args.args[1];
pr->pwm_conf.complementary =
pwm_args.args_count >= 3 && (pwm_args.args[2] & RT_BIT(0));
pr->enable_active_value = PIN_HIGH;
pr->enable_pin = rt_ofw_get_named_pin(np, "enable", 0,
RT_NULL, &pr->enable_active_value);
if (pr->enable_pin < 0 && pr->enable_pin != PIN_NONE)
{
err = pr->enable_pin;
goto _fail;
}
if (pr->enable_pin >= 0)
{
rt_bool_t on = pr->param.boot_on || pr->param.always_on;
rt_pin_mode(pr->enable_pin, PIN_MODE_OUTPUT);
rt_pin_write(pr->enable_pin, pwm_regulator_enable_pin_value(pr, on));
}
rgp = &pr->parent;
rgp->supply_name = pr->param.name;
rgp->param = &pr->param;
rgp->dev = &pdev->parent;
if (rt_ofw_prop_read_bool(np, "voltage-table"))
{
err = pwm_regulator_init_table(np, pr);
}
else
{
err = pwm_regulator_init_continuous(np, pr);
}
if (err)
{
goto _fail;
}
{
rt_uint32_t init_uvolt;
if (!rt_ofw_prop_read_u32(np, "regulator-init-microvolt", &init_uvolt))
{
if (init_uvolt < pr->param.min_uvolt ||
init_uvolt > pr->param.max_uvolt)
{
err = -RT_EINVAL;
goto _fail;
}
pr->init_uvolt = init_uvolt;
}
}
if ((err = pwm_regulator_adjust_config(pr)))
{
goto _fail;
}
if ((err = rt_regulator_register(rgp)))
{
goto _fail;
}
return RT_EOK;
_fail:
if (pr)
{
rt_free(pr->duty_cycle_table);
rt_free(pr);
}
return err;
}
static const struct rt_ofw_node_id pwm_regulator_ofw_ids[] = {
{ .compatible = "pwm-regulator" },
{ /* sentinel */ }
};
static struct rt_platform_driver pwm_regulator_driver = {
.name = "pwm-regulator",
.ids = pwm_regulator_ofw_ids,
.probe = pwm_regulator_probe,
};
RT_PLATFORM_DRIVER_EXPORT(pwm_regulator_driver);

View File

@ -25,16 +25,40 @@ struct rt_regulator
struct rt_regulator_record
{
rt_list_t list;
rt_list_t list;
struct rt_regulator_node *reg_np;
};
static RT_DEFINE_SPINLOCK(_regulator_lock);
static rt_list_t _regulator_records = RT_LIST_OBJECT_INIT(_regulator_records);
static struct rt_mutex _regulator_lock;
static rt_list_t _regulator_records = RT_LIST_OBJECT_INIT(_regulator_records);
static rt_err_t regulator_enable(struct rt_regulator_node *reg_np);
static rt_err_t regulator_disable(struct rt_regulator_node *reg_np);
static int regulator_init(void)
{
rt_mutex_init(&_regulator_lock, "REG", RT_IPC_FLAG_PRIO);
return RT_EOK;
}
INIT_CORE_EXPORT(regulator_init);
static void regulator_lock(void)
{
if (rt_thread_self())
{
rt_mutex_take(&_regulator_lock, RT_WAITING_FOREVER);
}
}
static void regulator_unlock(void)
{
if (rt_thread_self())
{
rt_mutex_release(&_regulator_lock);
}
}
static struct rt_regulator_record *regulator_find_record_by_name(const char *name)
{
struct rt_regulator_record *record = RT_NULL;
@ -67,8 +91,8 @@ static struct rt_regulator_record *regulator_find_record_by_node(struct rt_regul
rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
{
rt_err_t err;
struct rt_regulator_record *record;
rt_err_t err;
struct rt_regulator_record *record;
const struct rt_regulator_param *param;
if (!reg_np || !reg_np->dev || !reg_np->param || !reg_np->ops)
@ -96,11 +120,11 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
}
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
if (regulator_find_record_by_name(reg_np->supply_name))
{
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return -RT_EBUSY;
}
@ -108,7 +132,7 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
if (!record)
{
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return -RT_ENOMEM;
}
@ -116,7 +140,7 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
rt_list_init(&record->list);
rt_list_insert_before(&_regulator_records, &record->list);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
#ifdef RT_USING_OFW
if (reg_np->dev->ofw_node)
@ -127,7 +151,10 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
if (param->boot_on || param->always_on)
{
regulator_enable(reg_np);
if (!regulator_enable(reg_np) && param->always_on)
{
rt_atomic_store(&reg_np->enabled_count, 1);
}
}
return RT_EOK;
@ -135,7 +162,7 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np)
{
rt_err_t err = RT_EOK;
rt_err_t err = RT_EOK;
struct rt_regulator_record *record;
if (!reg_np)
@ -143,7 +170,7 @@ rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np)
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
if (rt_atomic_load(&reg_np->enabled_count) != 0)
{
@ -177,7 +204,7 @@ rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np)
}
_unlock:
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
if (!err && record)
{
@ -187,8 +214,8 @@ _unlock:
return err;
}
rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg,
struct rt_regulator_notifier *notifier)
rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg,
struct rt_regulator_notifier *notifier)
{
struct rt_regulator_node *reg_np;
@ -197,42 +224,42 @@ rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg,
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
reg_np = reg->reg_np;
reg_np = reg->reg_np;
notifier->regulator = reg;
rt_list_init(&notifier->list);
rt_list_insert_after(&reg_np->notifier_nodes, &notifier->list);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return RT_EOK;
}
rt_err_t rt_regulator_notifier_unregister(struct rt_regulator *reg,
struct rt_regulator_notifier *notifier)
rt_err_t rt_regulator_notifier_unregister(struct rt_regulator *reg,
struct rt_regulator_notifier *notifier)
{
if (!reg || !notifier)
{
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
rt_list_remove(&notifier->list);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return RT_EOK;
}
static rt_err_t regulator_notifier_call_chain(struct rt_regulator_node *reg_np,
rt_ubase_t msg, void *data)
rt_ubase_t msg, void *data)
{
rt_err_t err = RT_EOK;
rt_err_t err = RT_EOK;
struct rt_regulator_notifier *notifier;
rt_list_t *head = &reg_np->notifier_nodes;
rt_list_t *head = &reg_np->notifier_nodes;
if (rt_list_isempty(head))
{
@ -268,7 +295,7 @@ static rt_uint32_t regulator_get_enable_time(struct rt_regulator_node *reg_np)
}
static rt_uint32_t regulator_set_voltage_time(struct rt_regulator_node *reg_np,
int old_uvolt, int new_uvolt)
int old_uvolt, int new_uvolt)
{
unsigned int ramp_delay = 0;
@ -373,7 +400,7 @@ static rt_err_t regulator_enable(struct rt_regulator_node *reg_np)
rt_err_t rt_regulator_enable(struct rt_regulator *reg)
{
rt_err_t err;
int enabled_cnt;
int enabled_cnt;
if (!reg)
{
@ -386,19 +413,19 @@ rt_err_t rt_regulator_enable(struct rt_regulator *reg)
return RT_EOK;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
enabled_cnt = rt_atomic_load(&reg->reg_np->enabled_count);
if (enabled_cnt > 0)
{
rt_atomic_add(&reg->reg_np->enabled_count, 1);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return RT_EOK;
}
err = regulator_enable(reg->reg_np);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return err;
}
@ -407,6 +434,11 @@ static rt_err_t regulator_disable(struct rt_regulator_node *reg_np)
{
rt_err_t err = RT_EOK;
if (reg_np->param->always_on)
{
return RT_EOK;
}
if (reg_np->ops->disable)
{
err = reg_np->ops->disable(reg_np);
@ -433,7 +465,7 @@ static rt_err_t regulator_disable(struct rt_regulator_node *reg_np)
rt_err_t rt_regulator_disable(struct rt_regulator *reg)
{
rt_err_t err = RT_EOK;
int enabled_cnt;
int enabled_cnt;
if (!reg)
{
@ -445,9 +477,16 @@ rt_err_t rt_regulator_disable(struct rt_regulator *reg)
return RT_EOK;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
enabled_cnt = rt_atomic_load(&reg->reg_np->enabled_count);
if (reg->reg_np->param->always_on && enabled_cnt <= 1)
{
regulator_unlock();
return RT_EOK;
}
rt_atomic_sub(&reg->reg_np->enabled_count, 1);
if (enabled_cnt == 1)
@ -455,7 +494,7 @@ rt_err_t rt_regulator_disable(struct rt_regulator *reg)
err = regulator_disable(reg->reg_np);
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return err;
}
@ -467,6 +506,11 @@ rt_bool_t rt_regulator_is_enabled(struct rt_regulator *reg)
return RT_FALSE;
}
if (reg->reg_np->param->always_on)
{
return RT_TRUE;
}
if (reg->reg_np->ops->is_enabled)
{
return reg->reg_np->ops->is_enabled(reg->reg_np);
@ -499,7 +543,7 @@ static rt_err_t regulator_set_voltage(struct rt_regulator_node *reg_np, int min_
if (!err)
{
rt_uint32_t delay = regulator_set_voltage_time(reg_np,
args.old_uvolt, reg_np->ops->get_voltage(reg_np));
args.old_uvolt, reg_np->ops->get_voltage(reg_np));
if (delay)
{
@ -509,7 +553,7 @@ static rt_err_t regulator_set_voltage(struct rt_regulator_node *reg_np, int min_
else
{
regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR,
(void *)(rt_base_t)args.old_uvolt);
(void *)(rt_base_t)args.old_uvolt);
}
}
@ -581,18 +625,18 @@ rt_err_t rt_regulator_set_voltage(struct rt_regulator *reg, int min_uvolt, int m
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
err = regulator_set_voltage(reg->reg_np, min_uvolt, max_uvolt);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return err;
}
int rt_regulator_get_voltage(struct rt_regulator *reg)
{
int uvolt = RT_REGULATOR_UVOLT_INVALID;
int uvolt = RT_REGULATOR_UVOLT_INVALID;
struct rt_regulator_node *reg_np;
if (!reg)
@ -600,7 +644,7 @@ int rt_regulator_get_voltage(struct rt_regulator *reg)
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
reg_np = reg->reg_np;
@ -613,7 +657,7 @@ int rt_regulator_get_voltage(struct rt_regulator *reg)
uvolt = -RT_ENOSYS;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return uvolt;
}
@ -646,18 +690,18 @@ rt_err_t rt_regulator_set_current(struct rt_regulator *reg, int min_uamp, int ma
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
err = regulator_set_current(reg->reg_np, min_uamp, max_uamp);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return err;
}
int rt_regulator_get_current(struct rt_regulator *reg)
{
int uamp = RT_REGULATOR_UAMP_INVALID;
int uamp = RT_REGULATOR_UAMP_INVALID;
struct rt_regulator_node *reg_np;
if (!reg)
@ -665,7 +709,7 @@ int rt_regulator_get_current(struct rt_regulator *reg)
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
reg_np = reg->reg_np;
@ -678,14 +722,14 @@ int rt_regulator_get_current(struct rt_regulator *reg)
uamp = -RT_ENOSYS;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return uamp;
}
rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode)
{
rt_err_t err;
rt_err_t err;
struct rt_regulator_node *reg_np;
if (!reg)
@ -693,7 +737,7 @@ rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode)
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
reg_np = reg->reg_np;
@ -706,14 +750,14 @@ rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode)
err = -RT_ENOSYS;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return err;
}
rt_int32_t rt_regulator_get_mode(struct rt_regulator *reg)
{
rt_int32_t mode;
rt_int32_t mode;
struct rt_regulator_node *reg_np;
if (!reg)
@ -721,7 +765,7 @@ rt_int32_t rt_regulator_get_mode(struct rt_regulator *reg)
return -RT_EINVAL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
reg_np = reg->reg_np;
@ -734,7 +778,7 @@ rt_int32_t rt_regulator_get_mode(struct rt_regulator *reg)
mode = -RT_ENOSYS;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
return mode;
}
@ -747,9 +791,9 @@ static void regulator_check_parent(struct rt_regulator_node *reg_np)
}
else
{
#ifdef RT_USING_OFW
rt_phandle parent_phandle = 0;
struct rt_ofw_node *np = reg_np->dev->ofw_node;
#ifdef RT_USING_OFW
rt_phandle parent_phandle = 0;
struct rt_ofw_node *np = reg_np->dev->ofw_node;
while (np)
{
@ -766,7 +810,7 @@ static void regulator_check_parent(struct rt_regulator_node *reg_np)
if (!(reg_np->parent = rt_ofw_data(np)))
{
LOG_W("%s parent ofw node = %s not init",
reg_np->supply_name, rt_ofw_node_full_name(np));
reg_np->supply_name, rt_ofw_node_full_name(np));
rt_ofw_node_put(np);
break;
@ -775,13 +819,13 @@ static void regulator_check_parent(struct rt_regulator_node *reg_np)
rt_list_insert_after(&reg_np->parent->children_nodes, &reg_np->list);
rt_ofw_node_put(np);
}
#endif /* RT_USING_OFW */
#endif /* RT_USING_OFW */
}
}
struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id)
{
struct rt_regulator *reg = RT_NULL;
struct rt_regulator *reg = RT_NULL;
struct rt_regulator_node *reg_np = RT_NULL;
if (!id)
@ -793,9 +837,9 @@ struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id)
#ifdef RT_USING_OFW
if (dev && dev->ofw_node)
{
rt_phandle supply_phandle;
rt_phandle supply_phandle;
struct rt_ofw_node *np = dev->ofw_node;
char supply_name[64];
char supply_name[64];
rt_snprintf(supply_name, sizeof(supply_name), "%s-supply", id);
@ -824,13 +868,13 @@ struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id)
{
struct rt_regulator_record *record;
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
record = regulator_find_record_by_name(id);
if (record)
{
reg_np = record->reg_np;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
}
if (!reg_np)
@ -838,11 +882,11 @@ struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id)
goto _end;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
regulator_check_parent(reg_np);
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
reg = rt_calloc(1, sizeof(*reg));
@ -880,9 +924,9 @@ void rt_regulator_put(struct rt_regulator *reg)
struct rt_regulator_node **rt_regulator_nodes_snapshot(rt_size_t *count)
{
struct rt_regulator_record *record;
struct rt_regulator_node **nodes;
rt_size_t total = 0;
rt_size_t idx = 0;
struct rt_regulator_node **nodes;
rt_size_t total = 0;
rt_size_t idx = 0;
if (!count)
{
@ -891,12 +935,12 @@ struct rt_regulator_node **rt_regulator_nodes_snapshot(rt_size_t *count)
*count = 0;
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
rt_list_for_each_entry(record, &_regulator_records, list)
{
total++;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
if (!total)
{
@ -909,14 +953,14 @@ struct rt_regulator_node **rt_regulator_nodes_snapshot(rt_size_t *count)
return RT_NULL;
}
rt_hw_spin_lock(&_regulator_lock.lock);
regulator_lock();
rt_list_for_each_entry(record, &_regulator_records, list)
{
nodes[idx] = record->reg_np;
rt_ref_get(&record->reg_np->ref);
idx++;
}
rt_hw_spin_unlock(&_regulator_lock.lock);
regulator_unlock();
*count = total;
return nodes;