diff options
author | Maxime Ripard <maxime@cerno.tech> | 2020-05-27 17:47:32 +0200 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2020-06-16 14:19:57 +0200 |
commit | a9701376ed0fb61a5be4bb438daf26bd9cfa24b5 (patch) | |
tree | fc9c93aee04c97d35c490be563b940984cc4558c | |
parent | 9357b04624013294e4204b1a837d0a611b9048c3 (diff) |
reset: simple: Add reset callback
The reset-simple code lacks a reset callback that is still pretty easy to
implement. The only real thing to consider is the delay needed for a device
to be reset, so let's expose that as part of the reset-simple driver data.
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r-- | drivers/reset/reset-simple.c | 20 | ||||
-rw-r--r-- | include/linux/reset/reset-simple.h | 7 |
2 files changed, 27 insertions, 0 deletions
diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index c854aa351640..e066614818a3 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -11,6 +11,7 @@ * Maxime Ripard <maxime.ripard@free-electrons.com> */ +#include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/io.h> @@ -63,6 +64,24 @@ static int reset_simple_deassert(struct reset_controller_dev *rcdev, return reset_simple_update(rcdev, id, false); } +static int reset_simple_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_simple_data *data = to_reset_simple_data(rcdev); + int ret; + + if (!data->reset_us) + return -ENOTSUPP; + + ret = reset_simple_assert(rcdev, id); + if (ret) + return ret; + + usleep_range(data->reset_us, data->reset_us * 2); + + return reset_simple_deassert(rcdev, id); +} + static int reset_simple_status(struct reset_controller_dev *rcdev, unsigned long id) { @@ -80,6 +99,7 @@ static int reset_simple_status(struct reset_controller_dev *rcdev, const struct reset_control_ops reset_simple_ops = { .assert = reset_simple_assert, .deassert = reset_simple_deassert, + .reset = reset_simple_reset, .status = reset_simple_status, }; EXPORT_SYMBOL_GPL(reset_simple_ops); diff --git a/include/linux/reset/reset-simple.h b/include/linux/reset/reset-simple.h index 08ccb25a55e6..c3e44f45b0f7 100644 --- a/include/linux/reset/reset-simple.h +++ b/include/linux/reset/reset-simple.h @@ -27,6 +27,12 @@ * @status_active_low: if true, bits read back as cleared while the reset is * asserted. Otherwise, bits read back as set while the * reset is asserted. + * @reset_us: Minimum delay in microseconds needed that needs to be + * waited for between an assert and a deassert to reset the + * device. If multiple consumers with different delay + * requirements are connected to this controller, it must + * be the largest minimum delay. 0 means that such a delay is + * unknown and the reset operation is unsupported. */ struct reset_simple_data { spinlock_t lock; @@ -34,6 +40,7 @@ struct reset_simple_data { struct reset_controller_dev rcdev; bool active_low; bool status_active_low; + unsigned int reset_us; }; extern const struct reset_control_ops reset_simple_ops; |