Skip to content

Commit

Permalink
drivers: regulator: fixed regulator
Browse files Browse the repository at this point in the history
Implements fixed voltage level regulator driver to register DT
compatible "regulator-fixed" devices into the regulator framework.
These regulators may be enabled/disabled using a GPIO pin in which
cases CFG_DRIVERS_GPIO shall be enabled.

Acked-by: Gatien Chevallier <gatien.chevallier@foss.st.com>
Acked-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
Co-developed-by: Pascal Paillet <p.paillet@foss.st.com>
Signed-off-by: Pascal Paillet <p.paillet@foss.st.com>
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
  • Loading branch information
etienne-lms authored and jforissier committed Oct 11, 2023
1 parent b2d6db2 commit 652d2ce
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 0 deletions.
184 changes: 184 additions & 0 deletions core/drivers/regulator/regulator_fixed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2022-2023, STMicroelectronics
*/

#include <compiler.h>
#include <drivers/gpio.h>
#include <drivers/regulator.h>
#include <dt-bindings/gpio/gpio.h>
#include <kernel/delay.h>
#include <kernel/dt_driver.h>
#include <libfdt.h>
#include <tee_api_types.h>
#include <trace.h>

static_assert(GPIO_LEVEL_HIGH == 1 && GPIO_LEVEL_LOW == 0);

/*
* struct regulator_gpio - GPIO controlled regulator
* @regulator: Preallocated regulator instance
* @enable_gpio: GPIO for the enable state of the regulator or NULL if always on
* @enable_delay: Time (in microsecond) for the regulator to get enabled
* @off_on_delay: Min time (in microsecond) between enable and disable request
* @off_on_us: Timestamp of the last disable request
*/
struct regulator_fixed {
struct regulator regulator;
struct gpio *enable_gpio;
unsigned int enable_delay;
unsigned int off_on_delay;
uint64_t off_on_us;
};

static struct regulator_fixed *regulator_priv(struct regulator *regulator)
{
return container_of(regulator, struct regulator_fixed, regulator);
}

static TEE_Result fixed_set_state(struct regulator *regulator, bool enabled)
{
struct regulator_fixed *regu = regulator_priv(regulator);

if (regu->enable_gpio) {
if (enabled) {
while (!timeout_elapsed(regu->off_on_us))
udelay(1);
gpio_set_value(regu->enable_gpio, GPIO_LEVEL_HIGH);
udelay(regu->enable_delay);
} else {
regu->off_on_us = timeout_init_us(regu->off_on_delay);
gpio_set_value(regu->enable_gpio, GPIO_LEVEL_LOW);
}
}

return TEE_SUCCESS;
}

static TEE_Result fixed_get_state(struct regulator *regulator, bool *enabled)
{
struct regulator_fixed *regu = regulator_priv(regulator);

if (regu->enable_gpio)
*enabled = gpio_get_value(regu->enable_gpio);
else
*enabled = true;

return TEE_SUCCESS;
}

static const struct regulator_ops fixed_regulator_ops = {
.set_state = fixed_set_state,
.get_state = fixed_get_state,
};

static TEE_Result get_enable_gpio(const void *fdt, int node,
struct regulator_fixed *regu)
{
TEE_Result res = TEE_ERROR_GENERIC;
const fdt32_t *cuint = NULL;
struct gpio *gpio = NULL;
void *gpio_ref = &gpio;

res = dt_driver_device_from_node_idx_prop("gpios", fdt, node, 0,
DT_DRIVER_GPIO, gpio_ref);
if (res == TEE_ERROR_ITEM_NOT_FOUND)
res = dt_driver_device_from_node_idx_prop("gpio", fdt, node, 0,
DT_DRIVER_GPIO,
gpio_ref);
if (res == TEE_ERROR_ITEM_NOT_FOUND) {
regu->enable_gpio = NULL;

return TEE_SUCCESS;
}
if (res)
return res;

/* Override active level phandle flag, as per DT bindings */
if (dt_have_prop(fdt, node, "enable-active-high"))
gpio->dt_flags &= ~GPIO_ACTIVE_LOW;
else
gpio->dt_flags |= GPIO_ACTIVE_LOW;

/* Override open drain/open source phandle flag, as per DT bindings */
if (dt_have_prop(fdt, node, "gpio-open-drain"))
gpio->dt_flags |= GPIO_LINE_OPEN_DRAIN;
else
gpio->dt_flags &= ~GPIO_LINE_OPEN_DRAIN;

cuint = fdt_getprop(fdt, node, "startup-delay-us", NULL);
if (cuint)
regu->enable_delay = fdt32_to_cpu(*cuint);

cuint = fdt_getprop(fdt, node, "off-on-delay-us", NULL);
if (cuint)
regu->off_on_delay = fdt32_to_cpu(*cuint);

gpio_set_direction(gpio, GPIO_DIR_OUT);

regu->enable_gpio = gpio;

return TEE_SUCCESS;
}

static TEE_Result fixed_regulator_probe(const void *fdt, int node,
const void *compat_data __unused)
{
struct regulator_fixed *regu = NULL;
TEE_Result res = TEE_ERROR_GENERIC;
struct regu_dt_desc desc = { };
const char *supply_name = NULL;
const char *type = NULL;
char *regu_name = NULL;

regu_name = (char *)fdt_get_name(fdt, node, NULL);

type = fdt_getprop(fdt, node, "regulator-type", NULL);
if (type && strcmp(type, "voltage")) {
EMSG("Regulator gpio node %s: type %s not supported",
regu_name, type);
return TEE_ERROR_GENERIC;
}

regu = calloc(1, sizeof(*regu));
if (!regu)
return TEE_ERROR_OUT_OF_MEMORY;

res = get_enable_gpio(fdt, node, regu);
if (res)
goto err;

if (fdt_getprop(fdt, node, "vin-supply", NULL))
supply_name = "vin";

desc = (struct regu_dt_desc){
.name = regu_name,
.ops = &fixed_regulator_ops,
.supply_name = supply_name,
.regulator = &regu->regulator,
};

res = regulator_dt_register(fdt, node, node, &desc);
if (res) {
EMSG("Can't register regulator %s: %#"PRIx32, regu_name, res);
goto err;
}

return TEE_SUCCESS;

err:
free(regu);

return res;
}

static const struct dt_device_match regulator_match_table[] = {
{ .compatible = "regulator-fixed" },
{ }
};

DEFINE_DT_DRIVER(fixed_regulator_dt_driver) = {
.name = "regulator-fixed",
.match_table = regulator_match_table,
.probe = fixed_regulator_probe,
};
1 change: 1 addition & 0 deletions core/drivers/regulator/sub.mk
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
srcs-y += regulator.c
srcs-$(CFG_DT) += regulator_dt.c
srcs-$(CFG_REGULATOR_FIXED) += regulator_fixed.c
7 changes: 7 additions & 0 deletions mk/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,14 @@ CFG_DRIVERS_PINCTRL ?= n
# When enabled, CFG_DRIVERS_REGULATOR embeds a voltage regulator framework in
# OP-TEE core to provide drivers a common regulator interface and describe
# the regulators dependencies using an embedded device tree.
#
# When enabled, CFG_REGULATOR_FIXED embeds a voltage regulator driver for
# DT compatible "regulator-fixed" devices.
CFG_DRIVERS_REGULATOR ?= n
CFG_REGULATOR_FIXED ?= n

$(eval $(call cfg-enable-all-depends,CFG_REGULATOR_FIXED, \
CFG_DRIVERS_REGULATOR CFG_DT))

# The purpose of this flag is to show a print when booting up the device that
# indicates whether the board runs a standard developer configuration or not.
Expand Down

0 comments on commit 652d2ce

Please sign in to comment.