// SPDX-License-Identifier: GPL-2.0-or-later /* * Reset Controller framework * * Copyright 2013 Philipp Zabel, Pengutronix */ #include <linux/atomic.h> #include <linux/cleanup.h> #include <linux/device.h> #include <linux/err.h> #include <linux/export.h> #include <linux/kernel.h> #include <linux/kref.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> #include <linux/idr.h> #include <linux/module.h> #include <linux/of.h> #include <linux/acpi.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/reset-controller.h> #include <linux/slab.h> static DEFINE_MUTEX(reset_list_mutex); static LIST_HEAD(reset_controller_list); static DEFINE_MUTEX(reset_lookup_mutex); static LIST_HEAD(reset_lookup_list); /* Protects reset_gpio_lookup_list */ static DEFINE_MUTEX(reset_gpio_lookup_mutex); static LIST_HEAD(reset_gpio_lookup_list); static DEFINE_IDA(reset_gpio_ida); /** * struct reset_control - a reset control * @rcdev: a pointer to the reset controller device * this reset control belongs to * @list: list entry for the rcdev's reset controller list * @id: ID of the reset controller in the reset * controller device * @refcnt: Number of gets of this reset_control * @acquired: Only one reset_control may be acquired for a given rcdev and id. * @shared: Is this a shared (1), or an exclusive (0) reset_control? * @array: Is this an array of reset controls (1)? * @deassert_count: Number of times this reset line has been deasserted * @triggered_count: Number of times this reset line has been reset. Currently * only used for shared resets, which means that the value * will be either 0 or 1. */ struct reset_control { … }; /** * struct reset_control_array - an array of reset controls * @base: reset control for compatibility with reset control API functions * @num_rstcs: number of reset controls * @rstc: array of reset controls */ struct reset_control_array { … }; /** * struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices * @of_args: phandle to the reset controller with all the args like GPIO number * @list: list entry for the reset_gpio_lookup_list */ struct reset_gpio_lookup { … }; static const char *rcdev_name(struct reset_controller_dev *rcdev) { … } /** * of_reset_simple_xlate - translate reset_spec to the reset line number * @rcdev: a pointer to the reset controller device * @reset_spec: reset line specifier as found in the device tree * * This static translation function is used by default if of_xlate in * :c:type:`reset_controller_dev` is not set. It is useful for all reset * controllers with 1:1 mapping, where reset lines can be indexed by number * without gaps. */ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec) { … } /** * reset_controller_register - register a reset controller device * @rcdev: a pointer to the initialized reset controller device */ int reset_controller_register(struct reset_controller_dev *rcdev) { … } EXPORT_SYMBOL_GPL(…); /** * reset_controller_unregister - unregister a reset controller device * @rcdev: a pointer to the reset controller device */ void reset_controller_unregister(struct reset_controller_dev *rcdev) { … } EXPORT_SYMBOL_GPL(…); static void devm_reset_controller_release(struct device *dev, void *res) { … } /** * devm_reset_controller_register - resource managed reset_controller_register() * @dev: device that is registering this reset controller * @rcdev: a pointer to the initialized reset controller device * * Managed reset_controller_register(). For reset controllers registered by * this function, reset_controller_unregister() is automatically called on * driver detach. See reset_controller_register() for more information. */ int devm_reset_controller_register(struct device *dev, struct reset_controller_dev *rcdev) { … } EXPORT_SYMBOL_GPL(…); /** * reset_controller_add_lookup - register a set of lookup entries * @lookup: array of reset lookup entries * @num_entries: number of entries in the lookup array */ void reset_controller_add_lookup(struct reset_control_lookup *lookup, unsigned int num_entries) { … } EXPORT_SYMBOL_GPL(…); static inline struct reset_control_array * rstc_to_array(struct reset_control *rstc) { … } static int reset_control_array_reset(struct reset_control_array *resets) { … } static int reset_control_array_rearm(struct reset_control_array *resets) { … } static int reset_control_array_assert(struct reset_control_array *resets) { … } static int reset_control_array_deassert(struct reset_control_array *resets) { … } static int reset_control_array_acquire(struct reset_control_array *resets) { … } static void reset_control_array_release(struct reset_control_array *resets) { … } static inline bool reset_control_is_array(struct reset_control *rstc) { … } /** * reset_control_reset - reset the controlled device * @rstc: reset controller * * On a shared reset line the actual reset pulse is only triggered once for the * lifetime of the reset_control instance: for all but the first caller this is * a no-op. * Consumers must not use reset_control_(de)assert on shared reset lines when * reset_control_reset has been used. * * If rstc is NULL it is an optional reset and the function will just * return 0. */ int reset_control_reset(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * reset_control_assert - asserts the reset line * @rstc: reset controller * * Calling this on an exclusive reset controller guarantees that the reset * will be asserted. When called on a shared reset controller the line may * still be deasserted, as long as other users keep it so. * * For shared reset controls a driver cannot expect the hw's registers and * internal state to be reset, but must be prepared for this to happen. * Consumers must not use reset_control_reset on shared reset lines when * reset_control_(de)assert has been used. * * If rstc is NULL it is an optional reset and the function will just * return 0. */ int reset_control_assert(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * reset_control_deassert - deasserts the reset line * @rstc: reset controller * * After calling this function, the reset is guaranteed to be deasserted. * Consumers must not use reset_control_reset on shared reset lines when * reset_control_(de)assert has been used. * * If rstc is NULL it is an optional reset and the function will just * return 0. */ int reset_control_deassert(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * reset_control_status - returns a negative errno if not supported, a * positive value if the reset line is asserted, or zero if the reset * line is not asserted or if the desc is NULL (optional reset). * @rstc: reset controller */ int reset_control_status(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * reset_control_acquire() - acquires a reset control for exclusive use * @rstc: reset control * * This is used to explicitly acquire a reset control for exclusive use. Note * that exclusive resets are requested as acquired by default. In order for a * second consumer to be able to control the reset, the first consumer has to * release it first. Typically the easiest way to achieve this is to call the * reset_control_get_exclusive_released() to obtain an instance of the reset * control. Such reset controls are not acquired by default. * * Consumers implementing shared access to an exclusive reset need to follow * a specific protocol in order to work together. Before consumers can change * a reset they must acquire exclusive access using reset_control_acquire(). * After they are done operating the reset, they must release exclusive access * with a call to reset_control_release(). Consumers are not granted exclusive * access to the reset as long as another consumer hasn't released a reset. * * See also: reset_control_release() */ int reset_control_acquire(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * reset_control_release() - releases exclusive access to a reset control * @rstc: reset control * * Releases exclusive access right to a reset control previously obtained by a * call to reset_control_acquire(). Until a consumer calls this function, no * other consumers will be granted exclusive access. * * See also: reset_control_acquire() */ void reset_control_release(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); static struct reset_control * __reset_control_get_internal(struct reset_controller_dev *rcdev, unsigned int index, bool shared, bool acquired) { … } static void __reset_control_release(struct kref *kref) { … } static void __reset_control_put_internal(struct reset_control *rstc) { … } static int __reset_add_reset_gpio_lookup(int id, struct device_node *np, unsigned int gpio, unsigned int of_flags) { … } /* * @args: phandle to the GPIO provider with all the args like GPIO number */ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) { … } static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args, bool gpio_fallback) { … } struct reset_control * __of_reset_control_get(struct device_node *node, const char *id, int index, bool shared, bool optional, bool acquired) { … } EXPORT_SYMBOL_GPL(…); static struct reset_controller_dev * __reset_controller_by_name(const char *name) { … } static struct reset_control * __reset_control_get_from_lookup(struct device *dev, const char *con_id, bool shared, bool optional, bool acquired) { … } struct reset_control *__reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional, bool acquired) { … } EXPORT_SYMBOL_GPL(…); int __reset_control_bulk_get(struct device *dev, int num_rstcs, struct reset_control_bulk_data *rstcs, bool shared, bool optional, bool acquired) { … } EXPORT_SYMBOL_GPL(…); static void reset_control_array_put(struct reset_control_array *resets) { … } /** * reset_control_put - free the reset controller * @rstc: reset controller */ void reset_control_put(struct reset_control *rstc) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); static void devm_reset_control_release(struct device *dev, void *res) { … } struct reset_control * __devm_reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional, bool acquired) { … } EXPORT_SYMBOL_GPL(…); struct reset_control_bulk_devres { … }; static void devm_reset_control_bulk_release(struct device *dev, void *res) { … } int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, struct reset_control_bulk_data *rstcs, bool shared, bool optional, bool acquired) { … } EXPORT_SYMBOL_GPL(…); /** * __device_reset - find reset controller associated with the device * and perform reset * @dev: device to be reset by the controller * @optional: whether it is optional to reset the device * * Convenience wrapper for __reset_control_get() and reset_control_reset(). * This is useful for the common case of devices with single, dedicated reset * lines. _RST firmware method will be called for devices with ACPI. */ int __device_reset(struct device *dev, bool optional) { … } EXPORT_SYMBOL_GPL(…); /* * APIs to manage an array of reset controls. */ /** * of_reset_control_get_count - Count number of resets available with a device * * @node: device node that contains 'resets'. * * Returns positive reset count on success, or error number on failure and * on count being zero. */ static int of_reset_control_get_count(struct device_node *node) { … } /** * of_reset_control_array_get - Get a list of reset controls using * device node. * * @np: device node for the device that requests the reset controls array * @shared: whether reset controls are shared or not * @optional: whether it is optional to get the reset controls * @acquired: only one reset control may be acquired for a given controller * and ID * * Returns pointer to allocated reset_control on success or error on failure */ struct reset_control * of_reset_control_array_get(struct device_node *np, bool shared, bool optional, bool acquired) { … } EXPORT_SYMBOL_GPL(…); /** * devm_reset_control_array_get - Resource managed reset control array get * * @dev: device that requests the list of reset controls * @shared: whether reset controls are shared or not * @optional: whether it is optional to get the reset controls * * The reset control array APIs are intended for a list of resets * that just have to be asserted or deasserted, without any * requirements on the order. * * Returns pointer to allocated reset_control on success or error on failure */ struct reset_control * devm_reset_control_array_get(struct device *dev, bool shared, bool optional) { … } EXPORT_SYMBOL_GPL(…); static int reset_control_get_count_from_lookup(struct device *dev) { … } /** * reset_control_get_count - Count number of resets available with a device * * @dev: device for which to return the number of resets * * Returns positive reset count on success, or error number on failure and * on count being zero. */ int reset_control_get_count(struct device *dev) { … } EXPORT_SYMBOL_GPL(…);