Skip to content

Commit

Permalink
reset: Add reset_control_bulk API
Browse files Browse the repository at this point in the history
Follow the clock and regulator subsystems' lead and add a bulk API
for reset controls.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Tested-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20210314154459.15375-5-digetx@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Philipp Zabel authored and Mark Brown committed Mar 18, 2021
1 parent 0bbceca commit 48d7139
Show file tree
Hide file tree
Showing 2 changed files with 530 additions and 0 deletions.
215 changes: 215 additions & 0 deletions drivers/reset/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,30 @@ int reset_control_reset(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_reset);

/**
* reset_control_bulk_reset - reset the controlled devices in order
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Issue a reset on all provided reset controls, in order.
*
* See also: reset_control_reset()
*/
int reset_control_bulk_reset(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;

for (i = 0; i < num_rstcs; i++) {
ret = reset_control_reset(rstcs[i].rstc);
if (ret)
return ret;
}

return 0;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_reset);

/**
* reset_control_rearm - allow shared reset line to be re-triggered"
* @rstc: reset controller
Expand Down Expand Up @@ -461,6 +485,36 @@ int reset_control_assert(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_assert);

/**
* reset_control_bulk_assert - asserts the reset lines in order
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Assert the reset lines for all provided reset controls, in order.
* If an assertion fails, already asserted resets are deasserted again.
*
* See also: reset_control_assert()
*/
int reset_control_bulk_assert(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;

for (i = 0; i < num_rstcs; i++) {
ret = reset_control_assert(rstcs[i].rstc);
if (ret)
goto err;
}

return 0;

err:
while (i--)
reset_control_deassert(rstcs[i].rstc);
return ret;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_assert);

/**
* reset_control_deassert - deasserts the reset line
* @rstc: reset controller
Expand Down Expand Up @@ -511,6 +565,36 @@ int reset_control_deassert(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_deassert);

/**
* reset_control_bulk_deassert - deasserts the reset lines in reverse order
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Deassert the reset lines for all provided reset controls, in reverse order.
* If a deassertion fails, already deasserted resets are asserted again.
*
* See also: reset_control_deassert()
*/
int reset_control_bulk_deassert(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;

for (i = num_rstcs - 1; i >= 0; i--) {
ret = reset_control_deassert(rstcs[i].rstc);
if (ret)
goto err;
}

return 0;

err:
while (i < num_rstcs)
reset_control_assert(rstcs[i++].rstc);
return ret;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);

/**
* reset_control_status - returns a negative errno if not supported, a
* positive value if the reset line is asserted, or zero if the reset
Expand Down Expand Up @@ -588,6 +672,36 @@ int reset_control_acquire(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_acquire);

/**
* reset_control_bulk_acquire - acquires reset controls for exclusive use
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* This is used to explicitly acquire reset controls requested with
* reset_control_bulk_get_exclusive_release() for temporary exclusive use.
*
* See also: reset_control_acquire(), reset_control_bulk_release()
*/
int reset_control_bulk_acquire(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;

for (i = 0; i < num_rstcs; i++) {
ret = reset_control_acquire(rstcs[i].rstc);
if (ret)
goto err;
}

return 0;

err:
while (i--)
reset_control_release(rstcs[i].rstc);
return ret;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_acquire);

/**
* reset_control_release() - releases exclusive access to a reset control
* @rstc: reset control
Expand All @@ -610,6 +724,26 @@ void reset_control_release(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_release);

/**
* reset_control_bulk_release() - releases exclusive access to reset controls
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Releases exclusive access right to reset controls previously obtained by a
* call to reset_control_bulk_acquire().
*
* See also: reset_control_release(), reset_control_bulk_acquire()
*/
void reset_control_bulk_release(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int i;

for (i = 0; i < num_rstcs; i++)
reset_control_release(rstcs[i].rstc);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_release);

static struct reset_control *__reset_control_get_internal(
struct reset_controller_dev *rcdev,
unsigned int index, bool shared, bool acquired)
Expand Down Expand Up @@ -814,6 +948,32 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
}
EXPORT_SYMBOL_GPL(__reset_control_get);

int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired)
{
int ret, i;

for (i = 0; i < num_rstcs; i++) {
rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0,
shared, optional, acquired);
if (IS_ERR(rstcs[i].rstc)) {
ret = PTR_ERR(rstcs[i].rstc);
goto err;
}
}

return 0;

err:
mutex_lock(&reset_list_mutex);
while (i--)
__reset_control_put_internal(rstcs[i].rstc);
mutex_unlock(&reset_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(__reset_control_bulk_get);

static void reset_control_array_put(struct reset_control_array *resets)
{
int i;
Expand Down Expand Up @@ -845,6 +1005,23 @@ void reset_control_put(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_put);

/**
* reset_control_bulk_put - free the reset controllers
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*/
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
mutex_lock(&reset_list_mutex);
while (num_rstcs--) {
if (IS_ERR_OR_NULL(rstcs[num_rstcs].rstc))
continue;
__reset_control_put_internal(rstcs[num_rstcs].rstc);
}
mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_put);

static void devm_reset_control_release(struct device *dev, void *res)
{
reset_control_put(*(struct reset_control **)res);
Expand Down Expand Up @@ -874,6 +1051,44 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
}
EXPORT_SYMBOL_GPL(__devm_reset_control_get);

struct reset_control_bulk_devres {
int num_rstcs;
struct reset_control_bulk_data *rstcs;
};

static void devm_reset_control_bulk_release(struct device *dev, void *res)
{
struct reset_control_bulk_devres *devres = res;

reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
}

int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired)
{
struct reset_control_bulk_devres *ptr;
int ret;

ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;

ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired);
if (ret < 0) {
devres_free(ptr);
return ret;
}

ptr->num_rstcs = num_rstcs;
ptr->rstcs = rstcs;
devres_add(dev, ptr);

return 0;
}
EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get);

/**
* __device_reset - find reset controller associated with the device
* and perform reset
Expand Down
Loading

0 comments on commit 48d7139

Please sign in to comment.