[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:
parent
19e9be8779
commit
c19fe2c823
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = ®ulator_fixed_ops;
|
||||
rnp->param = &rf->param;
|
||||
rnp->dev = &pdev->parent;
|
||||
rnp->ops = ®ulator_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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 = ®ulator_gpio_ops;
|
||||
rgp->param = &rg->param;
|
||||
rgp->dev = &pdev->parent;
|
||||
rgp->ops = ®ulator_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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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, ¤t)))
|
||||
{
|
||||
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);
|
||||
|
|
@ -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(®_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(®_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(¬ifier->list);
|
||||
rt_list_insert_after(®_np->notifier_nodes, ¬ifier->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(¬ifier->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 = ®_np->notifier_nodes;
|
||||
rt_list_t *head = ®_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_np->enabled_count);
|
||||
if (enabled_cnt > 0)
|
||||
{
|
||||
rt_atomic_add(®->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_np->enabled_count);
|
||||
|
||||
if (reg->reg_np->param->always_on && enabled_cnt <= 1)
|
||||
{
|
||||
regulator_unlock();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_atomic_sub(®->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(®_np->parent->children_nodes, ®_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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue