diff options
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Kconfig | 3 | ||||
-rw-r--r-- | drivers/reset/core.c | 73 | ||||
-rw-r--r-- | drivers/reset/reset-meson.c | 8 | ||||
-rw-r--r-- | drivers/reset/reset-socfpga.c | 11 | ||||
-rw-r--r-- | drivers/reset/reset-ti-syscon.c | 4 |
5 files changed, 93 insertions, 6 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index dceec715e745..71ab75a46491 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -102,7 +102,8 @@ config RESET_LPC18XX This enables the reset controller driver for NXP LPC18xx/43xx SoCs. config RESET_MESON - bool "Meson Reset Driver" if COMPILE_TEST + tristate "Meson Reset Driver" + depends on ARCH_MESON || COMPILE_TEST default ARCH_MESON help This enables the reset driver for Amlogic Meson SoCs. diff --git a/drivers/reset/core.c b/drivers/reset/core.c index a2df88e90011..34e89aa0fb5e 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -208,6 +208,39 @@ static int reset_control_array_reset(struct reset_control_array *resets) return 0; } +static int reset_control_array_rearm(struct reset_control_array *resets) +{ + struct reset_control *rstc; + int i; + + for (i = 0; i < resets->num_rstcs; i++) { + rstc = resets->rstc[i]; + + if (!rstc) + continue; + + if (WARN_ON(IS_ERR(rstc))) + return -EINVAL; + + if (rstc->shared) { + if (WARN_ON(atomic_read(&rstc->deassert_count) != 0)) + return -EINVAL; + } else { + if (!rstc->acquired) + return -EPERM; + } + } + + for (i = 0; i < resets->num_rstcs; i++) { + rstc = resets->rstc[i]; + + if (rstc && rstc->shared) + WARN_ON(atomic_dec_return(&rstc->triggered_count) < 0); + } + + return 0; +} + static int reset_control_array_assert(struct reset_control_array *resets) { int ret, i; @@ -326,6 +359,46 @@ int reset_control_reset(struct reset_control *rstc) EXPORT_SYMBOL_GPL(reset_control_reset); /** + * reset_control_rearm - allow shared reset line to be re-triggered" + * @rstc: reset controller + * + * On a shared reset line the actual reset pulse is only triggered once for the + * lifetime of the reset_control instance, except if this call is used. + * + * Calls to this function must be balanced with calls to reset_control_reset, + * a warning is thrown in case triggered_count ever dips below 0. + * + * Consumers must not use reset_control_(de)assert on shared reset lines when + * reset_control_reset or reset_control_rearm have been used. + * + * If rstc is NULL the function will just return 0. + */ +int reset_control_rearm(struct reset_control *rstc) +{ + if (!rstc) + return 0; + + if (WARN_ON(IS_ERR(rstc))) + return -EINVAL; + + if (reset_control_is_array(rstc)) + return reset_control_array_rearm(rstc_to_array(rstc)); + + if (rstc->shared) { + if (WARN_ON(atomic_read(&rstc->deassert_count) != 0)) + return -EINVAL; + + WARN_ON(atomic_dec_return(&rstc->triggered_count) < 0); + } else { + if (!rstc->acquired) + return -EPERM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(reset_control_rearm); + +/** * reset_control_assert - asserts the reset line * @rstc: reset controller * diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 94d7ba88d7d2..c9bc325ad65a 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/slab.h> @@ -104,6 +105,7 @@ static const struct of_device_id meson_reset_dt_ids[] = { { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param}, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); static int meson_reset_probe(struct platform_device *pdev) { @@ -142,4 +144,8 @@ static struct platform_driver meson_reset_driver = { .of_match_table = meson_reset_dt_ids, }, }; -builtin_platform_driver(meson_reset_driver); +module_platform_driver(meson_reset_driver); + +MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver"); +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index bdd984296196..2a72f861f798 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -44,7 +44,7 @@ static int a10_reset_init(struct device_node *np) data->membase = ioremap(res.start, size); if (!data->membase) { ret = -ENOMEM; - goto err_alloc; + goto release_region; } if (of_property_read_u32(np, "altr,modrst-offset", ®_offset)) @@ -59,7 +59,14 @@ static int a10_reset_init(struct device_node *np) data->rcdev.of_node = np; data->status_active_low = true; - return reset_controller_register(&data->rcdev); + ret = reset_controller_register(&data->rcdev); + if (ret) + pr_err("unable to register device\n"); + + return ret; + +release_region: + release_mem_region(res.start, size); err_alloc: kfree(data); diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c index ef97c4dbbb4e..218370faf37b 100644 --- a/drivers/reset/reset-ti-syscon.c +++ b/drivers/reset/reset-ti-syscon.c @@ -89,7 +89,7 @@ static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev, mask = BIT(control->assert_bit); value = (control->flags & ASSERT_SET) ? mask : 0x0; - return regmap_update_bits(data->regmap, control->assert_offset, mask, value); + return regmap_write_bits(data->regmap, control->assert_offset, mask, value); } /** @@ -120,7 +120,7 @@ static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev, mask = BIT(control->deassert_bit); value = (control->flags & DEASSERT_SET) ? mask : 0x0; - return regmap_update_bits(data->regmap, control->deassert_offset, mask, value); + return regmap_write_bits(data->regmap, control->deassert_offset, mask, value); } /** |