devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Chao Xie <chao.xie@marvell.com>
To: haojian.zhuang@gmail.com, mturquette@linaro.org,
	chao.xie@marvell.com, xiechao_mail@163.com,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 09/12] clk: mmp: add spin lock automatic detection from device tree
Date: Tue, 10 Jun 2014 09:27:45 +0800	[thread overview]
Message-ID: <1402363668-25806-10-git-send-email-chao.xie@marvell.com> (raw)
In-Reply-To: <1402363668-25806-1-git-send-email-chao.xie@marvell.com>

From: Chao Xie <chao.xie@marvell.com>

For Marvell MMP series SOC, many clocks share same register.
In the operations of these clock, a spin lock is needed to avoid
confilicts.
When parse the clock from the device tree and register the clock,
we do not know whether it share the register with others.
So a common API is provided to get the spin lock for the clock based
on device tree support.
The general idea is record the node (clock device node, regsiter),
and before register a new clock, search the node list based on
register. If a node is found, return the shared spin lock, or create
a new.

Signed-off-by: Chao Xie <chao.xie@marvell.com>

Conflicts:
	drivers/clk/mmp/Makefile
---
 Documentation/devicetree/bindings/clock/mmp/lock |  44 +++++++
 drivers/clk/mmp/Makefile                         |   2 +-
 drivers/clk/mmp/clk.h                            |   5 +
 drivers/clk/mmp/lock.c                           | 159 +++++++++++++++++++++++
 4 files changed, 209 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/clock/mmp/lock
 create mode 100644 drivers/clk/mmp/lock.c

diff --git a/Documentation/devicetree/bindings/clock/mmp/lock b/Documentation/devicetree/bindings/clock/mmp/lock
new file mode 100644
index 0000000..7e7b5bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mmp/lock
@@ -0,0 +1,44 @@
+Binding of spin lock support for Marvell MMP series clock
+
+Because some clocks share same register, spinlock need to be used to avoid
+conflicts.
+
+The spin lock sharing detection is based on regsiter address, and it is
+automatically. To support some clocks, the spin lock is not based on
+register address, some properies are provided.
+The properites are used as part of clock's properties in clock device tree
+files.
+
+Optional properties:
+marvell,mmp-clk-spinlock-new : Skip the automatic detection based on
+			       register address. Direclty create a new
+			       spin lock.
+marvell,mmp-clk-spinlock : It is handle. It points to the clock that share
+			   same spin lock.
+
+Examples:
+
+Assume that clk1, clk2, clk3 share same spin lock.
+
+apmu_clk {
+	compatible = "marvell,mmp-clk-master";
+	...
+
+	clk1 {
+		...
+		marvell,mmp-clk-spinlock-new;
+		...
+	};
+
+	clk2 {
+		...
+		mmp-clk-spinlock = <&clk1>;
+		...
+	};
+
+	clk3 {
+		...
+		mmp-clk-spinlock = <&clk1>;
+		...
+	};
+};
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 518931e..e8810b6 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -6,7 +6,7 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o	\
 	 clk-mix-composite.o
 
 ifneq ($(CONFIG_OF),)
-obj-y += clk-master-node.o
+obj-y += clk-master-node.o lock.o
 endif
 
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 6d8c3b3..e06a228 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -147,6 +147,11 @@ extern void __iomem *of_mmp_clk_get_reg(struct device_node *np,
 struct device_node *of_mmp_clk_master_init(struct device_node *from);
 
 
+/* spin lock sharing support. */
+extern spinlock_t *of_mmp_clk_get_spinlock(struct device_node *np,
+					   unsigned int reg_base);
+
+
 extern struct clk *mmp_clk_register_pll2(const char *name,
 		const char *parent_name, unsigned long flags);
 extern struct clk *mmp_clk_register_apbc(const char *name,
diff --git a/drivers/clk/mmp/lock.c b/drivers/clk/mmp/lock.c
new file mode 100644
index 0000000..e2e246c
--- /dev/null
+++ b/drivers/clk/mmp/lock.c
@@ -0,0 +1,159 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <chao.xie@marvell.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+struct mmp_clk_spinlock_node {
+	struct device_node *share;
+	struct list_head node;
+};
+
+struct mmp_clk_spinlock {
+	spinlock_t lock;
+	struct device_node *owner;
+	unsigned int reg_base;
+	struct list_head share_list;
+	struct list_head node;
+};
+
+static LIST_HEAD(lock_list);
+
+static DEFINE_MUTEX(lock_mutex);
+
+static struct mmp_clk_spinlock_node *create_lock_node(struct device_node *np)
+{
+	struct mmp_clk_spinlock_node *node;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node) {
+		pr_err("%s:%s failed to allocate spinlock node.\n",
+			__func__, np->name);
+		return NULL;
+	}
+
+	node->share = np;
+
+	return node;
+}
+
+static struct mmp_clk_spinlock *create_lock(struct device_node *np,
+					    unsigned int reg_base)
+{
+	struct mmp_clk_spinlock *lock;
+
+	lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+	if (!lock) {
+		pr_err("%s:%s failed to allocate spinlock.\n",
+			__func__, np->name);
+		return NULL;
+	}
+
+	lock->owner = np;
+	lock->reg_base = reg_base;
+	INIT_LIST_HEAD(&lock->node);
+	INIT_LIST_HEAD(&lock->share_list);
+	spin_lock_init(&lock->lock);
+
+	return lock;
+}
+
+static struct mmp_clk_spinlock *find_lock_by_np(struct device_node *np)
+{
+	struct mmp_clk_spinlock *lock;
+
+	list_for_each_entry(lock, &lock_list, node) {
+		if (lock->owner == np)
+			return lock;
+	}
+
+	return NULL;
+}
+
+static struct mmp_clk_spinlock *find_lock_by_reg_base(unsigned int reg_base)
+{
+	struct mmp_clk_spinlock *lock;
+
+	list_for_each_entry(lock, &lock_list, node) {
+		if (lock->reg_base == reg_base)
+			return lock;
+	}
+
+	return NULL;
+}
+
+spinlock_t *of_mmp_clk_get_spinlock(struct device_node *np,
+					unsigned int reg_base)
+{
+	struct mmp_clk_spinlock *lock;
+	struct mmp_clk_spinlock_node *node;
+	struct device_node *owner;
+
+	if (of_property_read_bool(np, "marvell,mmp-clk-spinlock-new")) {
+
+		mutex_lock(&lock_mutex);
+
+		lock = find_lock_by_np(np);
+		if (!lock) {
+			lock = create_lock(np, reg_base);
+			if (lock)
+				list_add(&lock->node, &lock_list);
+		}
+
+		mutex_unlock(&lock_mutex);
+
+		return &lock->lock;
+	}
+
+	if (of_find_property(np, "marvell,mmp-clk-spinlock", NULL)) {
+
+		mutex_lock(&lock_mutex);
+
+		owner = of_parse_phandle(np, "marvell,mmp-clk-spinlock", 0);
+		lock = find_lock_by_np(owner);
+	} else {
+
+		mutex_lock(&lock_mutex);
+
+		lock = find_lock_by_reg_base(reg_base);
+	}
+
+	if (!lock) {
+		lock = create_lock(np, reg_base);
+		if (lock)
+			list_add(&lock->node, &lock_list);
+	}
+
+	if (!lock) {
+		mutex_unlock(&lock_mutex);
+		pr_err("%s:%s failed to get spinlock\n", __func__, np->name);
+		return NULL;
+	}
+
+	node = create_lock_node(np);
+	if (!node) {
+		mutex_unlock(&lock_mutex);
+		pr_err("%s:%s failed to create spinlock node\n",
+			__func__, np->name);
+		return NULL;
+	}
+	node->share = np;
+	list_add(&node->node, &lock->share_list);
+
+	mutex_unlock(&lock_mutex);
+
+	return &lock->lock;
+}
+
-- 
1.8.3.2

  parent reply	other threads:[~2014-06-10  1:27 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-10  1:27 [PATCH 00/12] clk: mmp: clock device tree support Chao Xie
2014-06-10  1:27 ` [PATCH 01/12] clk: mmp: add prefix "mmp" for structures defined for clk-frac Chao Xie
2014-06-10  1:27 ` [PATCH 02/12] clk: mmp: add spin lock " Chao Xie
     [not found] ` <1402363668-25806-1-git-send-email-chao.xie-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
2014-06-10  1:27   ` [PATCH 03/12] clk: mmp: add init callback " Chao Xie
2014-06-10  1:27 ` [PATCH 04/12] clk: mmp: move definiton of mmp_clk_frac to clk.h Chao Xie
2014-06-10  1:27 ` [PATCH 05/12] clk: mmp: add clock type mix Chao Xie
2014-06-10  1:27 ` [PATCH 06/12] clk: mmp: add mmp private gate clock Chao Xie
2014-06-10  1:27 ` [PATCH 07/12] clk: mmp: add clock type composite for mix Chao Xie
2014-06-10  1:27 ` [PATCH 08/12] clk: mmp: add clock type master Chao Xie
2014-06-10  1:27 ` Chao Xie [this message]
2014-06-10  1:27 ` [PATCH 10/12] clk: mmp: add device tree support for composite type clock Chao Xie
2014-06-10  1:27 ` [PATCH 11/12] clk: mmp: add device tree support for clocks Chao Xie
2014-06-10  1:27 ` [PATCH 12/12] arm: mmp: support clock device tree for mmp platforms Chao Xie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1402363668-25806-10-git-send-email-chao.xie@marvell.com \
    --to=chao.xie@marvell.com \
    --cc=devicetree@vger.kernel.org \
    --cc=haojian.zhuang@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mturquette@linaro.org \
    --cc=xiechao_mail@163.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).