Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8ed1e1a authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'reset-for-4.7' of git://git.pengutronix.de/git/pza/linux into next/drivers

Reset controller changes for v4.7

- add support for shared reset controls
- remove global variables from the lpc18xx driver

* tag 'reset-for-4.7' of git://git.pengutronix.de/git/pza/linux

:
  reset: lpc18xx: get rid of global variables for restart notifier
  reset: Add support for shared reset controls
  reset: Share struct reset_control between reset_control_get calls
  reset: Make [of_]reset_control_get[_foo] functions wrappers

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents f6396838 773fe726
Loading
Loading
Loading
Loading
+123 −94
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */
#include <linux/atomic.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -18,19 +19,27 @@
#include <linux/reset-controller.h>
#include <linux/slab.h>

static DEFINE_MUTEX(reset_controller_list_mutex);
static DEFINE_MUTEX(reset_list_mutex);
static LIST_HEAD(reset_controller_list);

/**
 * 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
 * @shared: Is this a shared (1), or an exclusive (0) reset_control?
 * @deassert_cnt: Number of times this reset line has been deasserted
 */
struct reset_control {
	struct reset_controller_dev *rcdev;
	struct list_head list;
	unsigned int id;
	unsigned int refcnt;
	int shared;
	atomic_t deassert_count;
};

/**
@@ -62,9 +71,11 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
		rcdev->of_xlate = of_reset_simple_xlate;
	}

	mutex_lock(&reset_controller_list_mutex);
	INIT_LIST_HEAD(&rcdev->reset_control_head);

	mutex_lock(&reset_list_mutex);
	list_add(&rcdev->list, &reset_controller_list);
	mutex_unlock(&reset_controller_list_mutex);
	mutex_unlock(&reset_list_mutex);

	return 0;
}
@@ -76,18 +87,23 @@ EXPORT_SYMBOL_GPL(reset_controller_register);
 */
void reset_controller_unregister(struct reset_controller_dev *rcdev)
{
	mutex_lock(&reset_controller_list_mutex);
	mutex_lock(&reset_list_mutex);
	list_del(&rcdev->list);
	mutex_unlock(&reset_controller_list_mutex);
	mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);

/**
 * reset_control_reset - reset the controlled device
 * @rstc: reset controller
 *
 * Calling this on a shared reset controller is an error.
 */
int reset_control_reset(struct reset_control *rstc)
{
	if (WARN_ON(rstc->shared))
		return -EINVAL;

	if (rstc->rcdev->ops->reset)
		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);

@@ -98,26 +114,48 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
/**
 * 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.
 */
int reset_control_assert(struct reset_control *rstc)
{
	if (rstc->rcdev->ops->assert)
		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);

	if (!rstc->rcdev->ops->assert)
		return -ENOTSUPP;

	if (rstc->shared) {
		if (WARN_ON(atomic_read(&rstc->deassert_count) == 0))
			return -EINVAL;

		if (atomic_dec_return(&rstc->deassert_count) != 0)
			return 0;
	}

	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_assert);

/**
 * reset_control_deassert - deasserts the reset line
 * @rstc: reset controller
 *
 * After calling this function, the reset is guaranteed to be deasserted.
 */
int reset_control_deassert(struct reset_control *rstc)
{
	if (rstc->rcdev->ops->deassert)
		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);

	if (!rstc->rcdev->ops->deassert)
		return -ENOTSUPP;

	if (rstc->shared) {
		if (atomic_inc_return(&rstc->deassert_count) != 1)
			return 0;
	}

	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_deassert);

@@ -136,18 +174,54 @@ int reset_control_status(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_status);

/**
 * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
 * controller by index.
 * @node: device to be reset by the controller
 * @index: index of the reset controller
 *
 * This is to be used to perform a list of resets for a device or power domain
 * in whatever order. Returns a struct reset_control or IS_ERR() condition
 * containing errno.
 */
struct reset_control *of_reset_control_get_by_index(struct device_node *node,
					   int index)
static struct reset_control *__reset_control_get(
				struct reset_controller_dev *rcdev,
				unsigned int index, int shared)
{
	struct reset_control *rstc;

	lockdep_assert_held(&reset_list_mutex);

	list_for_each_entry(rstc, &rcdev->reset_control_head, list) {
		if (rstc->id == index) {
			if (WARN_ON(!rstc->shared || !shared))
				return ERR_PTR(-EBUSY);

			rstc->refcnt++;
			return rstc;
		}
	}

	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
	if (!rstc)
		return ERR_PTR(-ENOMEM);

	try_module_get(rcdev->owner);

	rstc->rcdev = rcdev;
	list_add(&rstc->list, &rcdev->reset_control_head);
	rstc->id = index;
	rstc->refcnt = 1;
	rstc->shared = shared;

	return rstc;
}

static void __reset_control_put(struct reset_control *rstc)
{
	lockdep_assert_held(&reset_list_mutex);

	if (--rstc->refcnt)
		return;

	module_put(rstc->rcdev->owner);

	list_del(&rstc->list);
	kfree(rstc);
}

struct reset_control *__of_reset_control_get(struct device_node *node,
				     const char *id, int index, int shared)
{
	struct reset_control *rstc;
	struct reset_controller_dev *r, *rcdev;
@@ -155,12 +229,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
	int rstc_id;
	int ret;

	if (!node)
		return ERR_PTR(-EINVAL);

	if (id) {
		index = of_property_match_string(node,
						 "reset-names", id);
		if (index < 0)
			return ERR_PTR(-ENOENT);
	}

	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
					 index, &args);
	if (ret)
		return ERR_PTR(ret);

	mutex_lock(&reset_controller_list_mutex);
	mutex_lock(&reset_list_mutex);
	rcdev = NULL;
	list_for_each_entry(r, &reset_controller_list, list) {
		if (args.np == r->of_node) {
@@ -171,78 +255,29 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
	of_node_put(args.np);

	if (!rcdev) {
		mutex_unlock(&reset_controller_list_mutex);
		mutex_unlock(&reset_list_mutex);
		return ERR_PTR(-EPROBE_DEFER);
	}

	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
		mutex_unlock(&reset_controller_list_mutex);
		mutex_unlock(&reset_list_mutex);
		return ERR_PTR(-EINVAL);
	}

	rstc_id = rcdev->of_xlate(rcdev, &args);
	if (rstc_id < 0) {
		mutex_unlock(&reset_controller_list_mutex);
		mutex_unlock(&reset_list_mutex);
		return ERR_PTR(rstc_id);
	}

	try_module_get(rcdev->owner);
	mutex_unlock(&reset_controller_list_mutex);

	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
	if (!rstc) {
		module_put(rcdev->owner);
		return ERR_PTR(-ENOMEM);
	}
	/* reset_list_mutex also protects the rcdev's reset_control list */
	rstc = __reset_control_get(rcdev, rstc_id, shared);

	rstc->rcdev = rcdev;
	rstc->id = rstc_id;
	mutex_unlock(&reset_list_mutex);

	return rstc;
}
EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);

/**
 * of_reset_control_get - Lookup and obtain a reference to a reset controller.
 * @node: device to be reset by the controller
 * @id: reset line name
 *
 * Returns a struct reset_control or IS_ERR() condition containing errno.
 *
 * Use of id names is optional.
 */
struct reset_control *of_reset_control_get(struct device_node *node,
					   const char *id)
{
	int index = 0;

	if (id) {
		index = of_property_match_string(node,
						 "reset-names", id);
		if (index < 0)
			return ERR_PTR(-ENOENT);
	}
	return of_reset_control_get_by_index(node, index);
}
EXPORT_SYMBOL_GPL(of_reset_control_get);

/**
 * reset_control_get - Lookup and obtain a reference to a reset controller.
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Returns a struct reset_control or IS_ERR() condition containing errno.
 *
 * Use of id names is optional.
 */
struct reset_control *reset_control_get(struct device *dev, const char *id)
{
	if (!dev)
		return ERR_PTR(-EINVAL);

	return of_reset_control_get(dev->of_node, id);
}
EXPORT_SYMBOL_GPL(reset_control_get);
EXPORT_SYMBOL_GPL(__of_reset_control_get);

/**
 * reset_control_put - free the reset controller
@@ -254,8 +289,9 @@ void reset_control_put(struct reset_control *rstc)
	if (IS_ERR(rstc))
		return;

	module_put(rstc->rcdev->owner);
	kfree(rstc);
	mutex_lock(&reset_list_mutex);
	__reset_control_put(rstc);
	mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_control_put);

@@ -264,16 +300,8 @@ static void devm_reset_control_release(struct device *dev, void *res)
	reset_control_put(*(struct reset_control **)res);
}

/**
 * devm_reset_control_get - resource managed reset_control_get()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get(). For reset controllers returned from this
 * function, reset_control_put() is called automatically on driver detach.
 * See reset_control_get() for more information.
 */
struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
struct reset_control *__devm_reset_control_get(struct device *dev,
				     const char *id, int index, int shared)
{
	struct reset_control **ptr, *rstc;

@@ -282,7 +310,8 @@ struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
	if (!ptr)
		return ERR_PTR(-ENOMEM);

	rstc = reset_control_get(dev, id);
	rstc = __of_reset_control_get(dev ? dev->of_node : NULL,
				      id, index, shared);
	if (!IS_ERR(rstc)) {
		*ptr = rstc;
		devres_add(dev, ptr);
@@ -292,7 +321,7 @@ struct reset_control *devm_reset_control_get(struct device *dev, const char *id)

	return rstc;
}
EXPORT_SYMBOL_GPL(devm_reset_control_get);
EXPORT_SYMBOL_GPL(__devm_reset_control_get);

/**
 * device_reset - find reset controller associated with the device
+10 −12
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@

struct lpc18xx_rgu_data {
	struct reset_controller_dev rcdev;
	struct notifier_block restart_nb;
	struct clk *clk_delay;
	struct clk *clk_reg;
	void __iomem *base;
@@ -44,12 +45,13 @@ struct lpc18xx_rgu_data {

#define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev)

static void __iomem *rgu_base;

static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode,
static int lpc18xx_rgu_restart(struct notifier_block *nb, unsigned long mode,
			       void *cmd)
{
	writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0);
	struct lpc18xx_rgu_data *rc = container_of(nb, struct lpc18xx_rgu_data,
						   restart_nb);

	writel(BIT(LPC18XX_RGU_CORE_RST), rc->base + LPC18XX_RGU_CTRL0);
	mdelay(2000);

	pr_emerg("%s: unable to restart system\n", __func__);
@@ -57,11 +59,6 @@ static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode,
	return NOTIFY_DONE;
}

static struct notifier_block lpc18xx_rgu_restart_nb = {
	.notifier_call = lpc18xx_rgu_restart,
	.priority = 192,
};

/*
 * The LPC18xx RGU has mostly self-deasserting resets except for the
 * two reset lines going to the internal Cortex-M0 cores.
@@ -205,8 +202,9 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev)
		goto dis_clks;
	}

	rgu_base = rc->base;
	ret = register_restart_handler(&lpc18xx_rgu_restart_nb);
	rc->restart_nb.priority = 192,
	rc->restart_nb.notifier_call = lpc18xx_rgu_restart,
	ret = register_restart_handler(&rc->restart_nb);
	if (ret)
		dev_warn(&pdev->dev, "failed to register restart handler\n");

@@ -225,7 +223,7 @@ static int lpc18xx_rgu_remove(struct platform_device *pdev)
	struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev);
	int ret;

	ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb);
	ret = unregister_restart_handler(&rc->restart_nb);
	if (ret)
		dev_warn(&pdev->dev, "failed to unregister restart handler\n");

+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ struct of_phandle_args;
 * @ops: a pointer to device specific struct reset_control_ops
 * @owner: kernel module of the reset controller driver
 * @list: internal list of reset controller devices
 * @reset_control_head: head of internal list of requested reset controls
 * @of_node: corresponding device tree node as phandle target
 * @of_reset_n_cells: number of cells in reset line specifiers
 * @of_xlate: translation function to translate from specifier as found in the
@@ -41,6 +42,7 @@ struct reset_controller_dev {
	const struct reset_control_ops *ops;
	struct module *owner;
	struct list_head list;
	struct list_head reset_control_head;
	struct device_node *of_node;
	int of_reset_n_cells;
	int (*of_xlate)(struct reset_controller_dev *rcdev,
+154 −34
Original line number Diff line number Diff line
#ifndef _LINUX_RESET_H_
#define _LINUX_RESET_H_

struct device;
struct device_node;
#include <linux/device.h>

struct reset_control;

#ifdef CONFIG_RESET_CONTROLLER
@@ -12,9 +12,11 @@ int reset_control_assert(struct reset_control *rstc);
int reset_control_deassert(struct reset_control *rstc);
int reset_control_status(struct reset_control *rstc);

struct reset_control *reset_control_get(struct device *dev, const char *id);
struct reset_control *__of_reset_control_get(struct device_node *node,
				     const char *id, int index, int shared);
void reset_control_put(struct reset_control *rstc);
struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
struct reset_control *__devm_reset_control_get(struct device *dev,
				     const char *id, int index, int shared);

int __must_check device_reset(struct device *dev);

@@ -23,24 +25,6 @@ static inline int device_reset_optional(struct device *dev)
	return device_reset(dev);
}

static inline struct reset_control *reset_control_get_optional(
					struct device *dev, const char *id)
{
	return reset_control_get(dev, id);
}

static inline struct reset_control *devm_reset_control_get_optional(
					struct device *dev, const char *id)
{
	return devm_reset_control_get(dev, id);
}

struct reset_control *of_reset_control_get(struct device_node *node,
					   const char *id);

struct reset_control *of_reset_control_get_by_index(
					struct device_node *node, int index);

#else

static inline int reset_control_reset(struct reset_control *rstc)
@@ -77,44 +61,180 @@ static inline int device_reset_optional(struct device *dev)
	return -ENOTSUPP;
}

static inline struct reset_control *__must_check reset_control_get(
					struct device *dev, const char *id)
static inline struct reset_control *__of_reset_control_get(
					struct device_node *node,
					const char *id, int index, int shared)
{
	WARN_ON(1);
	return ERR_PTR(-EINVAL);
}

static inline struct reset_control *__must_check devm_reset_control_get(
static inline struct reset_control *__devm_reset_control_get(
					struct device *dev,
					const char *id, int index, int shared)
{
	return ERR_PTR(-EINVAL);
}

#endif /* CONFIG_RESET_CONTROLLER */

/**
 * reset_control_get - Lookup and obtain an exclusive reference to a
 *                     reset controller.
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Returns a struct reset_control or IS_ERR() condition containing errno.
 * If this function is called more then once for the same reset_control it will
 * return -EBUSY.
 *
 * See reset_control_get_shared for details on shared references to
 * reset-controls.
 *
 * Use of id names is optional.
 */
static inline struct reset_control *__must_check reset_control_get(
					struct device *dev, const char *id)
{
#ifndef CONFIG_RESET_CONTROLLER
	WARN_ON(1);
	return ERR_PTR(-EINVAL);
#endif
	return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0);
}

static inline struct reset_control *reset_control_get_optional(
					struct device *dev, const char *id)
{
	return ERR_PTR(-ENOTSUPP);
	return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0);
}

static inline struct reset_control *devm_reset_control_get_optional(
/**
 * reset_control_get_shared - Lookup and obtain a shared reference to a
 *                            reset controller.
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Returns a struct reset_control or IS_ERR() condition containing errno.
 * This function is intended for use with reset-controls which are shared
 * between hardware-blocks.
 *
 * When a reset-control is shared, the behavior of reset_control_assert /
 * deassert is changed, the reset-core will keep track of a deassert_count
 * and only (re-)assert the reset after reset_control_assert has been called
 * as many times as reset_control_deassert was called. Also see the remark
 * about shared reset-controls in the reset_control_assert docs.
 *
 * Calling reset_control_assert without first calling reset_control_deassert
 * is not allowed on a shared reset control. Calling reset_control_reset is
 * also not allowed on a shared reset control.
 *
 * Use of id names is optional.
 */
static inline struct reset_control *reset_control_get_shared(
					struct device *dev, const char *id)
{
	return ERR_PTR(-ENOTSUPP);
	return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1);
}

/**
 * of_reset_control_get - Lookup and obtain an exclusive reference to a
 *                        reset controller.
 * @node: device to be reset by the controller
 * @id: reset line name
 *
 * Returns a struct reset_control or IS_ERR() condition containing errno.
 *
 * Use of id names is optional.
 */
static inline struct reset_control *of_reset_control_get(
				struct device_node *node, const char *id)
{
	return ERR_PTR(-ENOTSUPP);
	return __of_reset_control_get(node, id, 0, 0);
}

/**
 * of_reset_control_get_by_index - Lookup and obtain an exclusive reference to
 *                                 a reset controller by index.
 * @node: device to be reset by the controller
 * @index: index of the reset controller
 *
 * This is to be used to perform a list of resets for a device or power domain
 * in whatever order. Returns a struct reset_control or IS_ERR() condition
 * containing errno.
 */
static inline struct reset_control *of_reset_control_get_by_index(
					struct device_node *node, int index)
{
	return ERR_PTR(-ENOTSUPP);
	return __of_reset_control_get(node, NULL, index, 0);
}

#endif /* CONFIG_RESET_CONTROLLER */
/**
 * devm_reset_control_get - resource managed reset_control_get()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get(). For reset controllers returned from this
 * function, reset_control_put() is called automatically on driver detach.
 * See reset_control_get() for more information.
 */
static inline struct reset_control *__must_check devm_reset_control_get(
					struct device *dev, const char *id)
{
#ifndef CONFIG_RESET_CONTROLLER
	WARN_ON(1);
#endif
	return __devm_reset_control_get(dev, id, 0, 0);
}

static inline struct reset_control *devm_reset_control_get_optional(
					struct device *dev, const char *id)
{
	return __devm_reset_control_get(dev, id, 0, 0);
}

/**
 * devm_reset_control_get_by_index - resource managed reset_control_get
 * @dev: device to be reset by the controller
 * @index: index of the reset controller
 *
 * Managed reset_control_get(). For reset controllers returned from this
 * function, reset_control_put() is called automatically on driver detach.
 * See reset_control_get() for more information.
 */
static inline struct reset_control *devm_reset_control_get_by_index(
					struct device *dev, int index)
{
	return __devm_reset_control_get(dev, NULL, index, 0);
}

/**
 * devm_reset_control_get_shared - resource managed reset_control_get_shared()
 * @dev: device to be reset by the controller
 * @id: reset line name
 *
 * Managed reset_control_get_shared(). For reset controllers returned from
 * this function, reset_control_put() is called automatically on driver detach.
 * See reset_control_get_shared() for more information.
 */
static inline struct reset_control *devm_reset_control_get_shared(
					struct device *dev, const char *id)
{
	return __devm_reset_control_get(dev, id, 0, 1);
}

/**
 * devm_reset_control_get_shared_by_index - resource managed
 * reset_control_get_shared
 * @dev: device to be reset by the controller
 * @index: index of the reset controller
 *
 * Managed reset_control_get_shared(). For reset controllers returned from
 * this function, reset_control_put() is called automatically on driver detach.
 * See reset_control_get_shared() for more information.
 */
static inline struct reset_control *devm_reset_control_get_shared_by_index(
					struct device *dev, int index)
{
	return __devm_reset_control_get(dev, NULL, index, 1);
}

#endif