sunxi: initial 4.4 support
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu> SVN-Revision: 48161
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
From d25cfe9b4f9663216ce4e011e3f1e7fa669ab58a Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Fri, 27 Nov 2015 21:09:05 +0100
|
||||
Subject: [PATCH] reset: Add shared reset_control_[de]assert variants
|
||||
|
||||
Add reset_control_deassert_shared / reset_control_assert_shared
|
||||
functions which are intended for use by drivers for hw blocks which
|
||||
(may) share a reset line with another driver / hw block.
|
||||
|
||||
Unlike the regular reset_control_[de]assert functions these functions
|
||||
keep track of how often deassert_shared / assert_shared have been called
|
||||
and keep the line deasserted as long as deassert has been called more
|
||||
times than assert.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
Changes in v2:
|
||||
-This is a new patch in v2 of this patch-set
|
||||
---
|
||||
drivers/reset/core.c | 121 ++++++++++++++++++++++++++++++++++++---
|
||||
include/linux/reset-controller.h | 2 +
|
||||
include/linux/reset.h | 2 +
|
||||
3 files changed, 116 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
|
||||
index 9ab9290..8c3436c 100644
|
||||
--- a/drivers/reset/core.c
|
||||
+++ b/drivers/reset/core.c
|
||||
@@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
|
||||
static LIST_HEAD(reset_controller_list);
|
||||
|
||||
/**
|
||||
+ * struct reset_line - a reset line
|
||||
+ * @list: list entry for the reset controllers reset line list
|
||||
+ * @id: ID of the reset line in the reset controller device
|
||||
+ * @refcnt: Number of reset_control structs referencing this device
|
||||
+ * @deassert_cnt: Number of times this reset line has been deasserted
|
||||
+ */
|
||||
+struct reset_line {
|
||||
+ struct list_head list;
|
||||
+ unsigned int id;
|
||||
+ unsigned int refcnt;
|
||||
+ unsigned int deassert_cnt;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* struct reset_control - a reset control
|
||||
* @rcdev: a pointer to the reset controller device
|
||||
* this reset control belongs to
|
||||
- * @id: ID of the reset controller in the reset
|
||||
- * controller device
|
||||
+ * @line: reset line for this reset control
|
||||
*/
|
||||
struct reset_control {
|
||||
struct reset_controller_dev *rcdev;
|
||||
+ struct reset_line *line;
|
||||
struct device *dev;
|
||||
- unsigned int id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -66,6 +79,8 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
|
||||
rcdev->of_xlate = of_reset_simple_xlate;
|
||||
}
|
||||
|
||||
+ INIT_LIST_HEAD(&rcdev->reset_line_head);
|
||||
+
|
||||
mutex_lock(&reset_controller_list_mutex);
|
||||
list_add(&rcdev->list, &reset_controller_list);
|
||||
mutex_unlock(&reset_controller_list_mutex);
|
||||
@@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unregister);
|
||||
int reset_control_reset(struct reset_control *rstc)
|
||||
{
|
||||
if (rstc->rcdev->ops->reset)
|
||||
- return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
|
||||
+ return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
@@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
|
||||
int reset_control_assert(struct reset_control *rstc)
|
||||
{
|
||||
if (rstc->rcdev->ops->assert)
|
||||
- return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
|
||||
+ return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
@@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
|
||||
int reset_control_deassert(struct reset_control *rstc)
|
||||
{
|
||||
if (rstc->rcdev->ops->deassert)
|
||||
- return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
|
||||
+ return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reset_control_deassert);
|
||||
|
||||
/**
|
||||
+ * reset_control_assert_shared - asserts a shared reset line
|
||||
+ * @rstc: reset controller
|
||||
+ *
|
||||
+ * Assert a shared reset line, this functions decreases the deassert count
|
||||
+ * of the line by one and asserts it if, and only if, the deassert count
|
||||
+ * reaches 0.
|
||||
+ */
|
||||
+int reset_control_assert_shared(struct reset_control *rstc)
|
||||
+{
|
||||
+ if (!rstc->rcdev->ops->assert)
|
||||
+ return -ENOTSUPP;
|
||||
+
|
||||
+ rstc->line->deassert_cnt--;
|
||||
+ if (rstc->line->deassert_cnt)
|
||||
+ return 0;
|
||||
+
|
||||
+ return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(reset_control_assert_shared);
|
||||
+
|
||||
+/**
|
||||
+ * reset_control_deassert_shared - deasserts a shared reset line
|
||||
+ * @rstc: reset controller
|
||||
+ *
|
||||
+ * Assert a shared reset line, this functions increases the deassert count
|
||||
+ * of the line by one and deasserts the reset line (if it was not already
|
||||
+ * deasserted).
|
||||
+ */
|
||||
+int reset_control_deassert_shared(struct reset_control *rstc)
|
||||
+{
|
||||
+ if (!rstc->rcdev->ops->deassert)
|
||||
+ return -ENOTSUPP;
|
||||
+
|
||||
+ rstc->line->deassert_cnt++;
|
||||
+ if (rstc->line->deassert_cnt != 1)
|
||||
+ return 0;
|
||||
+
|
||||
+ return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
|
||||
+
|
||||
+/**
|
||||
* 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.
|
||||
@@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
|
||||
int reset_control_status(struct reset_control *rstc)
|
||||
{
|
||||
if (rstc->rcdev->ops->status)
|
||||
- return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
|
||||
+ return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reset_control_status);
|
||||
|
||||
+static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
|
||||
+ unsigned int index)
|
||||
+{
|
||||
+ struct reset_line *line;
|
||||
+
|
||||
+ list_for_each_entry(line, &rcdev->reset_line_head, list) {
|
||||
+ if (line->id == index) {
|
||||
+ line->refcnt++;
|
||||
+ return line;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ line = kzalloc(sizeof(*line), GFP_KERNEL);
|
||||
+ if (!line)
|
||||
+ return NULL;
|
||||
+
|
||||
+ list_add(&line->list, &rcdev->reset_line_head);
|
||||
+ line->id = index;
|
||||
+ line->refcnt = 1;
|
||||
+
|
||||
+ return line;
|
||||
+}
|
||||
+
|
||||
+static void reset_line_put(struct reset_line *line)
|
||||
+{
|
||||
+ if (!line)
|
||||
+ return;
|
||||
+
|
||||
+ if (--line->refcnt)
|
||||
+ return;
|
||||
+
|
||||
+ list_del(&line->list);
|
||||
+ kfree(line);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* of_reset_control_get_by_index - Lookup and obtain a reference to a reset
|
||||
* controller by index.
|
||||
@@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
|
||||
{
|
||||
struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
|
||||
struct reset_controller_dev *r, *rcdev;
|
||||
+ struct reset_line *line;
|
||||
struct of_phandle_args args;
|
||||
int rstc_id;
|
||||
int ret;
|
||||
@@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
|
||||
}
|
||||
|
||||
try_module_get(rcdev->owner);
|
||||
+
|
||||
+ /* reset_controller_list_mutex also protects the reset_line list */
|
||||
+ line = reset_line_get(rcdev, rstc_id);
|
||||
+
|
||||
mutex_unlock(&reset_controller_list_mutex);
|
||||
|
||||
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
|
||||
- if (!rstc) {
|
||||
+ if (!line || !rstc) {
|
||||
+ kfree(rstc);
|
||||
+ reset_line_put(line);
|
||||
module_put(rcdev->owner);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
rstc->rcdev = rcdev;
|
||||
- rstc->id = rstc_id;
|
||||
+ rstc->line = line;
|
||||
|
||||
return rstc;
|
||||
}
|
||||
@@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
|
||||
if (IS_ERR(rstc))
|
||||
return;
|
||||
|
||||
+ mutex_lock(&reset_controller_list_mutex);
|
||||
+ reset_line_put(rstc->line);
|
||||
+ mutex_unlock(&reset_controller_list_mutex);
|
||||
+
|
||||
module_put(rstc->rcdev->owner);
|
||||
kfree(rstc);
|
||||
}
|
||||
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
|
||||
index ce6b962..7f2cbd1 100644
|
||||
--- a/include/linux/reset-controller.h
|
||||
+++ b/include/linux/reset-controller.h
|
||||
@@ -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_line_head: head of internal list of reset lines
|
||||
* @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 {
|
||||
struct reset_control_ops *ops;
|
||||
struct module *owner;
|
||||
struct list_head list;
|
||||
+ struct list_head reset_line_head;
|
||||
struct device_node *of_node;
|
||||
int of_reset_n_cells;
|
||||
int (*of_xlate)(struct reset_controller_dev *rcdev,
|
||||
diff --git a/include/linux/reset.h b/include/linux/reset.h
|
||||
index c4c097d..1cca8ce 100644
|
||||
--- a/include/linux/reset.h
|
||||
+++ b/include/linux/reset.h
|
||||
@@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
|
||||
int reset_control_assert(struct reset_control *rstc);
|
||||
int reset_control_deassert(struct reset_control *rstc);
|
||||
int reset_control_status(struct reset_control *rstc);
|
||||
+int reset_control_assert_shared(struct reset_control *rstc);
|
||||
+int reset_control_deassert_shared(struct reset_control *rstc);
|
||||
|
||||
struct reset_control *reset_control_get(struct device *dev, const char *id);
|
||||
void reset_control_put(struct reset_control *rstc);
|
||||
Reference in New Issue
Block a user