mirror of
https://github.com/apache/nuttx.git
synced 2026-08-18 19:50:47 +08:00
drivers/power: Describe the regulators through procfs.
The regulator framework has no way out to userspace: consumers reach a rail by name from inside the kernel, which is the right interface for controlling one, but it leaves a board with regulators offering no way to see what they are doing, and a newly written regulator driver cannot be looked at without writing a consumer for it first. Adds /proc/regulator, behind REGULATOR_PROCFS, listing every registered regulator: its present voltage, the range it will accept, whether it is enabled, how many consumers hold and enable it, its supply, and whether it is always on or expected on at boot. Lines carry the same key:value tokens in the same order, so the file is machine parseable. The last two are worth reading beside the consumer count, since a rail enabled with no consumers is expected rather than suspect when either is set. A part usually measures more than the framework has fields for, so struct regulator_ops_s gains an optional describe method: it writes key:value text and the renderer appends it to that rail's line. This is how a driver reports what only it knows, an input voltage, an output current, a temperature or a fault word, without the framework growing a field per part or the driver growing procfs code of its own. It is called with the list mutex held and never from interrupt context, so reading the part over a bus is allowed. The voltage and the enabled state are read back from the hardware rather than recalled, so a rail the boot loader set and nothing has touched since reads as it actually is. Both calls can fail, and a failure reports - rather than an errno formatted as a voltage or a rail that looks switched on. Reading the hardware is also why this takes the list mutex directly rather than calling regulator_list_lock(), which additionally disables interrupts so that callers in interrupt or idle context are safe. Asking a regulator on a bus what it is doing means a transfer, and a transfer waits; a task reading a file can afford to wait and an interrupt handler cannot. procfs_register() appends without checking for duplicates, so the entry is claimed once for the lifetime of the system rather than whenever the list is empty. It also needs FS_PROCFS_REGISTER, which the option now depends on rather than only FS_PROCFS. Documents the framework, which had no page at all: the consumer interface and what counted enables mean, what a driver supplies, and the new entry. The entry is read only. What voltage a rail may be is knowledge its consumers hold, and arranging the order between them is what the framework is for, so moving one from a shell would step around the part that matters. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <justin@dynam.ac>
This commit is contained in:
committed by
Xiang Xiao
parent
e29db6724c
commit
69386aa6c0
@@ -6,4 +6,5 @@ Power-related Drivers
|
||||
:caption: Supported Drivers
|
||||
|
||||
pm/index.rst
|
||||
regulator.rst
|
||||
battery/fakegauge.rst
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
==================
|
||||
Regulator Drivers
|
||||
==================
|
||||
|
||||
A regulator is a power rail whose voltage or on/off state software can
|
||||
control: a PMIC output, a switching converter, or a load switch driven by a
|
||||
GPIO. Drivers rarely want to own one outright, because a rail usually feeds
|
||||
more than one peripheral, so the framework arbitrates between the consumers of
|
||||
a rail rather than letting each drive it directly.
|
||||
|
||||
``include/nuttx/power/consumer.h`` declares what a consumer uses;
|
||||
``include/nuttx/power/regulator.h`` declares what a regulator driver
|
||||
implements. ``CONFIG_REGULATOR`` builds the framework.
|
||||
|
||||
Consumer interface
|
||||
==================
|
||||
|
||||
A consumer looks a regulator up by name, holds it while it needs the rail,
|
||||
and puts it back:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
FAR struct regulator_s *reg;
|
||||
|
||||
reg = regulator_get("vdd-sensor");
|
||||
if (reg == NULL)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regulator_set_voltage(reg, 1800000, 1800000); /* microvolts */
|
||||
regulator_enable(reg);
|
||||
...
|
||||
regulator_disable(reg);
|
||||
regulator_put(reg);
|
||||
|
||||
``regulator_get()``
|
||||
Look up a regulator by the name its driver registered, and return a handle
|
||||
on it. Each handle is one consumer's claim.
|
||||
|
||||
``regulator_enable()`` and ``regulator_disable()``
|
||||
Ask for the rail to be on or off. These are counted: the rail is switched
|
||||
on for the first consumer that enables it and off once the last one has
|
||||
disabled it, so a driver need not know who else is using it.
|
||||
|
||||
``regulator_set_voltage()``
|
||||
Ask for a voltage, as a range in microvolts. The framework intersects the
|
||||
ranges every consumer has asked for, so a rail shared between a part that
|
||||
needs 1.8 V and one that tolerates 1.7 V to 1.9 V settles where both are
|
||||
satisfied.
|
||||
|
||||
``regulator_get_voltage()``
|
||||
Read the rail's present voltage, in microvolts.
|
||||
|
||||
``regulator_is_enabled()``
|
||||
Report whether the rail is on.
|
||||
|
||||
``regulator_put()``
|
||||
Give the handle back and drop this consumer's claim.
|
||||
|
||||
Because the framework counts consumers, a driver should hold a rail for
|
||||
exactly as long as it needs it, and should not assume that disabling it turns
|
||||
anything off.
|
||||
|
||||
Writing a regulator driver
|
||||
==========================
|
||||
|
||||
A driver describes its regulator with a ``struct regulator_desc_s``, provides
|
||||
a ``struct regulator_ops_s``, and calls ``regulator_register()``. The
|
||||
descriptor carries the rail's name, the voltage range it will accept, and how
|
||||
it behaves at start up:
|
||||
|
||||
================ ========================================================
|
||||
Member Meaning
|
||||
================ ========================================================
|
||||
``name`` The name consumers pass to ``regulator_get()``
|
||||
``min_uv`` Lowest voltage the rail will accept
|
||||
``max_uv`` Highest voltage the rail will accept
|
||||
``supply_name`` The regulator feeding this one, if any
|
||||
``boot_on`` The rail is expected to be on already at start up
|
||||
``always_on`` The rail must never be switched off
|
||||
``apply_uv`` Apply a voltage during initialisation
|
||||
================ ========================================================
|
||||
|
||||
The remaining members describe the hardware to the generic helpers: the
|
||||
register and mask for voltage selection and for enabling, the step size and
|
||||
count for a linear rail, and the ramp and enable delays the framework waits
|
||||
out after a change.
|
||||
|
||||
``describe`` is the one operation that exists only for reporting. A part
|
||||
often measures more than the framework has fields for, and this is where that
|
||||
goes: write ``key:value`` text and the ``/proc/regulator`` renderer appends it
|
||||
to the rail's line. It is called with the list mutex held and never from
|
||||
interrupt context, so reading the part over a bus is allowed.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static int mychip_describe(FAR struct regulator_dev_s *rdev,
|
||||
FAR char *extra, size_t len)
|
||||
{
|
||||
FAR struct mychip_dev_s *priv = rdev->priv;
|
||||
|
||||
snprintf(extra, len, "vin:%d iout:%d temp:%d",
|
||||
priv->vin_uv, priv->iout_ua, priv->temp_mc);
|
||||
return OK;
|
||||
}
|
||||
|
||||
The operations are all optional; a regulator with no ``is_enabled`` is treated
|
||||
as always on, and one with no ``get_voltage`` reports the first entry of its
|
||||
voltage list. A GPIO controlled load switch needs only ``enable``,
|
||||
``disable`` and ``is_enabled``.
|
||||
|
||||
``regulator_unregister()`` removes a regulator; its consumers must have put
|
||||
their handles back first.
|
||||
|
||||
/proc/regulator
|
||||
===============
|
||||
|
||||
The framework has no character device: consumers reach a rail from inside the
|
||||
kernel, which is the right interface for controlling one but leaves no way to
|
||||
see what the rails are doing. ``CONFIG_REGULATOR_PROCFS`` adds
|
||||
``/proc/regulator``, listing every registered regulator:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
vdd-cpux uv:900000 min:800000 max:900000 enabled:1 users:1 opens:1 supply:- always_on:1 boot_on:1
|
||||
vdd-sensor uv:1800000 min:1700000 max:1900000 enabled:0 users:0 opens:0 supply:vsys always_on:0 boot_on:0
|
||||
|
||||
Every line carries the same ``key:value`` tokens in the same order, so the
|
||||
file can be parsed as well as read:
|
||||
|
||||
================ ========================================================
|
||||
Token Meaning
|
||||
================ ========================================================
|
||||
``uv`` Present voltage in microvolts, or ``-`` if unreadable
|
||||
``min``, ``max`` The range the regulator will accept
|
||||
``enabled`` Whether the rail is on, or ``-`` if unreadable
|
||||
``users`` Consumers currently enabling it
|
||||
``opens`` Handles currently held on it
|
||||
``supply`` The regulator feeding this one, or ``-``
|
||||
``always_on`` Set if the rail must never be switched off
|
||||
``boot_on`` Set if the rail is expected on at start up
|
||||
================ ========================================================
|
||||
|
||||
A driver implementing ``describe`` adds its own ``key:value`` fields after
|
||||
those, so a part that measures its input voltage, output current or
|
||||
temperature reports them on the same line:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
npu_vdd uv:800000 min:600000 max:1100000 enabled:1 users:1 opens:1 supply:- always_on:1 boot_on:0 vin:12043750 iout:3200000 temp:47500 status:0x0000
|
||||
|
||||
``always_on`` and ``boot_on`` are worth reading beside ``users``: a rail that
|
||||
is enabled with no consumers is expected rather than suspect when either is
|
||||
set.
|
||||
|
||||
The voltage and the enabled state are read back from the hardware rather than
|
||||
recalled, so a rail the boot loader set and nothing has touched since reads as
|
||||
it actually is. For a regulator on a bus that means a transfer per rail per
|
||||
read, which is why the entry takes the list mutex rather than the framework's
|
||||
own lock: that one also disables interrupts, and a bus transfer waits.
|
||||
|
||||
The entry is read only. What voltage a rail may be is knowledge its consumers
|
||||
hold, and arranging the order between them is what the framework is for, so
|
||||
moving one from a shell would step around the part that matters.
|
||||
|
||||
The option depends on ``FS_PROCFS_REGISTER`` and is off by default.
|
||||
|
||||
Remote regulators
|
||||
=================
|
||||
|
||||
``CONFIG_REGULATOR_RPMSG`` lets a consumer on one core use a regulator owned
|
||||
by another, over rpmsg. The core that owns the hardware runs
|
||||
``regulator_rpmsg_server_init()``; consumers use the ordinary interface either
|
||||
way.
|
||||
@@ -59,6 +59,25 @@ config REGULATOR
|
||||
|
||||
if REGULATOR
|
||||
|
||||
config REGULATOR_PROCFS
|
||||
bool "Describe the regulators through procfs"
|
||||
default n
|
||||
depends on FS_PROCFS && FS_PROCFS_REGISTER
|
||||
---help---
|
||||
Report every registered regulator through /proc/regulator: its
|
||||
name, the voltage it is putting out, the range it will accept,
|
||||
whether it is enabled, how many consumers hold it, its supply
|
||||
and whether it is always on or enabled at boot.
|
||||
|
||||
The voltage is read back from the hardware rather than recalled,
|
||||
so a rail left somewhere by the boot loader reads as it actually
|
||||
is rather than as this software last set it.
|
||||
|
||||
The entry is read only. A rail is not something to move by
|
||||
writing to a file: what a voltage may be is knowledge the
|
||||
consumers hold, and the ordering between them is what the
|
||||
framework exists to arrange.
|
||||
|
||||
config REGULATOR_GPIO
|
||||
bool "Regulator gpio driver support"
|
||||
default n
|
||||
|
||||
@@ -38,6 +38,13 @@
|
||||
#include <nuttx/power/consumer.h>
|
||||
#include <nuttx/signal.h>
|
||||
|
||||
#ifdef CONFIG_REGULATOR_PROCFS
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
# include <nuttx/fs/fs.h>
|
||||
# include <nuttx/fs/procfs.h>
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
@@ -73,6 +80,291 @@ static rmutex_t g_reg_lock = NXRMUTEX_INITIALIZER;
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_REGULATOR_PROCFS
|
||||
|
||||
/****************************************************************************
|
||||
* Name: regulator_procfs_open
|
||||
*
|
||||
* Description:
|
||||
* Read only. A rail is not something to move by writing to a file: the
|
||||
* consumers hold the knowledge of what a voltage may be, and the ordering
|
||||
* between them is the whole point of the framework. Reporting is what
|
||||
* this entry is for.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - The file structure to attach the open file to
|
||||
* relpath - The path below /proc being opened
|
||||
* oflags - Open flags; anything but read only is refused
|
||||
* mode - Ignored, the entry cannot be created
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success, or a negated errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int regulator_procfs_open(FAR struct file *filep,
|
||||
FAR const char *relpath,
|
||||
int oflags, mode_t mode)
|
||||
{
|
||||
FAR struct procfs_file_s *priv;
|
||||
|
||||
if ((oflags & O_ACCMODE) != O_RDONLY)
|
||||
{
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct procfs_file_s));
|
||||
if (priv == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
filep->f_priv = priv;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: regulator_procfs_close
|
||||
*
|
||||
* Description:
|
||||
* Close /proc/regulator and free what open() allocated.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - The open file
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success, or a negated errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int regulator_procfs_close(FAR struct file *filep)
|
||||
{
|
||||
kmm_free(filep->f_priv);
|
||||
filep->f_priv = NULL;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: regulator_procfs_read
|
||||
*
|
||||
* Description:
|
||||
* Describe every registered regulator: what it is called, what it is
|
||||
* putting out, the range it will accept, whether it is on and how many
|
||||
* consumers are holding it.
|
||||
*
|
||||
* The voltage is read from the hardware rather than remembered, so a rail
|
||||
* moved by something other than this framework, which is the usual state
|
||||
* of affairs at start up, is reported as it is rather than as this
|
||||
* software last left it.
|
||||
*
|
||||
* That is why this takes the list mutex directly rather than calling
|
||||
* regulator_list_lock(), which also disables interrupts for the benefit
|
||||
* of callers that may run in interrupt or idle context. Asking a
|
||||
* regulator on a bus what it is doing means bus traffic, and bus traffic
|
||||
* waits; a reader of this file is always a task and can afford to.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - The open file, carrying the offset reached so far
|
||||
* buffer - Where to return the text
|
||||
* buflen - Size of buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* The number of bytes returned, zero at end of file, or a negated errno
|
||||
* on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t regulator_procfs_read(FAR struct file *filep,
|
||||
FAR char *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct regulator_dev_s *rdev;
|
||||
size_t remaining = buflen;
|
||||
FAR char *dest = buffer;
|
||||
off_t pos = filep->f_pos;
|
||||
char line[192];
|
||||
char extra[48];
|
||||
size_t n;
|
||||
int ret;
|
||||
|
||||
ret = nxrmutex_lock(&g_reg_lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_for_every_entry(&g_reg_list, rdev, struct regulator_dev_s, list)
|
||||
{
|
||||
FAR const struct regulator_desc_s *desc = rdev->desc;
|
||||
int enabled;
|
||||
int uv;
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
n = snprintf(line, sizeof(line), "%-20s",
|
||||
desc->name != NULL ? desc->name : "-");
|
||||
|
||||
/* Both of these reach the hardware and can fail; a failure reports
|
||||
* - rather than an errno formatted as a voltage, or as a rail that
|
||||
* is switched on.
|
||||
*/
|
||||
|
||||
uv = _regulator_get_voltage(rdev);
|
||||
if (uv >= 0)
|
||||
{
|
||||
n += snprintf(line + n, sizeof(line) - n, " uv:%d", uv);
|
||||
}
|
||||
else
|
||||
{
|
||||
n += snprintf(line + n, sizeof(line) - n, " uv:-");
|
||||
}
|
||||
|
||||
n += snprintf(line + n, sizeof(line) - n, " min:%u max:%u",
|
||||
desc->min_uv, desc->max_uv);
|
||||
|
||||
enabled = _regulator_is_enabled(rdev);
|
||||
if (enabled >= 0)
|
||||
{
|
||||
n += snprintf(line + n, sizeof(line) - n, " enabled:%d",
|
||||
enabled != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
n += snprintf(line + n, sizeof(line) - n, " enabled:-");
|
||||
}
|
||||
|
||||
n += snprintf(line + n, sizeof(line) - n,
|
||||
" users:%" PRIu32 " opens:%" PRIu32
|
||||
" supply:%s always_on:%u boot_on:%u",
|
||||
rdev->use_count, rdev->open_count,
|
||||
desc->supply_name != NULL ? desc->supply_name : "-",
|
||||
desc->always_on, desc->boot_on);
|
||||
|
||||
/* Whatever the driver has that the fields above cannot hold. The
|
||||
* lock this runs under is the list mutex rather than the framework's
|
||||
* own, so a driver reading its part over a bus is allowed to wait.
|
||||
*/
|
||||
|
||||
extra[0] = '\0';
|
||||
if (rdev->ops->describe != NULL &&
|
||||
rdev->ops->describe(rdev, extra, sizeof(extra)) >= 0)
|
||||
{
|
||||
extra[sizeof(extra) - 1] = '\0';
|
||||
if (extra[0] != '\0')
|
||||
{
|
||||
n += snprintf(line + n, sizeof(line) - n, " %s", extra);
|
||||
}
|
||||
}
|
||||
|
||||
n += snprintf(line + n, sizeof(line) - n, "\n");
|
||||
|
||||
/* snprintf() reports the length it wanted, so a line longer than
|
||||
* the buffer would otherwise carry n past it.
|
||||
*/
|
||||
|
||||
if (n >= sizeof(line))
|
||||
{
|
||||
n = sizeof(line) - 1;
|
||||
line[n - 1] = '\n';
|
||||
}
|
||||
|
||||
n = procfs_memcpy(line, n, dest, remaining, &pos);
|
||||
dest += n;
|
||||
remaining -= n;
|
||||
}
|
||||
|
||||
nxrmutex_unlock(&g_reg_lock);
|
||||
|
||||
filep->f_pos += dest - buffer;
|
||||
return dest - buffer;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: regulator_procfs_dup
|
||||
*
|
||||
* Description:
|
||||
* Duplicate an open /proc/regulator, copying the position reached
|
||||
* so that the new file continues where the old one had got to.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oldp - The open file being duplicated
|
||||
* newp - The file structure to attach the duplicate to
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success, or a negated errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int regulator_procfs_dup(FAR const struct file *oldp,
|
||||
FAR struct file *newp)
|
||||
{
|
||||
FAR struct procfs_file_s *priv;
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct procfs_file_s));
|
||||
if (priv == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(priv, oldp->f_priv, sizeof(struct procfs_file_s));
|
||||
newp->f_priv = priv;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: regulator_procfs_stat
|
||||
*
|
||||
* Description:
|
||||
* Report /proc/regulator as a read only regular file.
|
||||
*
|
||||
* Input Parameters:
|
||||
* relpath - The path below /proc being queried
|
||||
* buf - Where to return the status
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success, or a negated errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int regulator_procfs_stat(FAR const char *relpath,
|
||||
FAR struct stat *buf)
|
||||
{
|
||||
buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
|
||||
buf->st_size = 0;
|
||||
buf->st_blksize = 0;
|
||||
buf->st_blocks = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static const struct procfs_operations g_regulator_procfs_ops =
|
||||
{
|
||||
regulator_procfs_open, /* open */
|
||||
regulator_procfs_close, /* close */
|
||||
regulator_procfs_read, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* poll */
|
||||
|
||||
regulator_procfs_dup, /* dup */
|
||||
|
||||
NULL, /* opendir */
|
||||
NULL, /* closedir */
|
||||
NULL, /* readdir */
|
||||
NULL, /* rewinddir */
|
||||
|
||||
regulator_procfs_stat, /* stat */
|
||||
};
|
||||
|
||||
static const struct procfs_entry_s g_regulator_procfs =
|
||||
{
|
||||
"regulator", &g_regulator_procfs_ops, PROCFS_FILE_TYPE
|
||||
};
|
||||
|
||||
static bool g_regulator_procfs_added;
|
||||
|
||||
#endif /* CONFIG_REGULATOR_PROCFS */
|
||||
|
||||
static int _regulator_is_enabled(FAR struct regulator_dev_s *rdev)
|
||||
{
|
||||
if (!rdev->ops->is_enabled)
|
||||
@@ -1092,6 +1384,24 @@ bypass:
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_REGULATOR_PROCFS
|
||||
/* procfs_register() has to run before procfs is mounted, which holds
|
||||
* here: regulators register during board or architecture start up. The
|
||||
* first one to arrive publishes the entry for all of them.
|
||||
*/
|
||||
|
||||
/* procfs_register() appends without checking for a duplicate, so the
|
||||
* entry is claimed once for the lifetime of the system rather than
|
||||
* whenever the list is empty.
|
||||
*/
|
||||
|
||||
if (!g_regulator_procfs_added)
|
||||
{
|
||||
procfs_register(&g_regulator_procfs);
|
||||
g_regulator_procfs_added = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
list_add_tail(&g_reg_list, &rdev->list);
|
||||
|
||||
out:
|
||||
|
||||
@@ -93,6 +93,24 @@ struct regulator_ops_s
|
||||
enum regulator_mode_e mode);
|
||||
CODE int (*set_suspend_voltage)(FAR struct regulator_dev_s *, int uv);
|
||||
CODE int (*resume)(FAR struct regulator_dev_s *rdev);
|
||||
|
||||
/* Report what this regulator can say about itself that the upper half
|
||||
* has no field for: what a particular part measures or latches, such as
|
||||
* its input voltage, output current, temperature or fault status.
|
||||
*
|
||||
* Optional. A regulator whose driver omits it is still listed with
|
||||
* everything the upper half knows: its voltage, its range, whether it
|
||||
* is enabled and how many consumers hold it.
|
||||
*
|
||||
* Write at most len bytes into extra as further key:value fields, in
|
||||
* the form the renderer uses, and return OK. The renderer owns the
|
||||
* line and appends this to it, so a driver needs no procfs knowledge
|
||||
* of its own. Called with the framework's list lock held and not from
|
||||
* interrupt context, so reading a part over a bus is allowed.
|
||||
*/
|
||||
|
||||
CODE int (*describe)(FAR struct regulator_dev_s *rdev, FAR char *extra,
|
||||
size_t len);
|
||||
};
|
||||
|
||||
/* This structure describes the regulators capabilities */
|
||||
|
||||
Reference in New Issue
Block a user