new file mode 100644
@@ -0,0 +1,49 @@
+Generic hwlock bindings
+=======================
+
+Generic bindings that are common to all the hwlock platform specific driver
+implementations, the retrieved values are used for registering the device
+specific parameters with the hwspinlock core.
+
+The validity and need of these common properties may vary from one platform
+implementation to another. The platform specific bindings should explicitly
+state if a property is mandatory or optional. Please look through the
+individual platform specific hwlock binding documentations for identifying
+the applicable properties.
+
+Common properties:
+- hwlock-num-locks: Number of locks present in a hwlock device. This
+ property is needed on hwlock devices, where the number
+ of supported locks within a hwlock device cannot be
+ read from a register.
+
+Hwlock Users:
+=============
+
+Nodes that require specific hwlock(s) should specify them using one or more
+properties, each containing a phandle to the hwlock node and a 0-indexed
+relative hwlock number within that hwlock node. Multiple hwlocks can be
+requested using an array of the phandle and hwlock number specifier tuple.
+
+1. Example of a node using a single specific hwlock:
+
+The following example has a node requesting third hwlock in the bank
+defined by the node hwlock1.
+
+ node {
+ ...
+ hwlocks = <&hwlock1 2>;
+ ...
+ };
+
+2. Example of a node using multiple specific hwlocks:
+
+The following example has a node requesting two hwlocks, third hwlock within
+the hwlock device node 'hwlock1', and the first hwlock within the hwlock
+device node 'hwlock2'.
+
+ node {
+ ...
+ hwlocks = <&hwlock1 2>, <&hwlock2 0>;
+ ...
+ };
@@ -1,7 +1,7 @@
/*
* Hardware spinlock framework
*
- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com
*
* Contact: Ohad Ben-Cohen <ohad@wizery.com>
*
@@ -27,6 +27,7 @@
#include <linux/hwspinlock.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include "hwspinlock_internal.h"
@@ -262,6 +263,33 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
}
EXPORT_SYMBOL_GPL(__hwspin_unlock);
+/**
+ * of_hwspin_lock_get_num_locks() - OF helper to retrieve number of locks
+ * @dn: device node pointer
+ *
+ * This is an OF helper function that can be called by the underlying
+ * platform-specific implementations, to retrieve the number of locks
+ * present within a hwspinlock device instance. The hwlock-num-locks
+ * DT property may be optional for some platforms, while mandatory for
+ * some others, so this function is typically called only by needed
+ * platform-specific implementations.
+ *
+ * Returns a positive number of locks on success, -ENODEV on generic
+ * failure or an appropriate error code as returned by the OF layer
+ */
+int of_hwspin_lock_get_num_locks(struct device_node *dn)
+{
+ unsigned int val;
+ int ret = -ENODEV;
+
+ ret = of_property_read_u32(dn, "hwlock-num-locks", &val);
+ if (!ret)
+ ret = val ? val : -ENODEV;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_hwspin_lock_get_num_locks);
+
static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
{
struct hwspinlock *tmp;
@@ -589,6 +617,61 @@ out:
EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
/**
+ * of_hwspin_lock_request_specific() - request a OF phandle-based specific lock
+ * @np: device node from which to request the specific hwlock
+ * @propname: property name containing hwlock specifier(s)
+ * @index: index of the hwlock
+ *
+ * This function is the OF equivalent of hwspin_lock_request_specific(). This
+ * function provides a means for users of the hwspinlock module to request a
+ * specific hwspinlock using the phandle of the hwspinlock device. The requested
+ * lock number is indexed relative to the hwspinlock device, unlike the
+ * hwspin_lock_request_specific() which is an absolute lock number.
+ *
+ * Returns the address of the assigned hwspinlock, or NULL on error
+ */
+struct hwspinlock *of_hwspin_lock_request_specific(struct device_node *np,
+ const char *propname, int index)
+{
+ struct hwspinlock_device *bank;
+ struct of_phandle_args args;
+ unsigned int id;
+ int ret;
+
+ ret = of_parse_phandle_with_fixed_args(np, propname, 1, index, &args);
+ if (ret) {
+ pr_warn("%s: can't parse hwlocks property of node '%s[%d]' ret = %d\n",
+ __func__, np->full_name, index, ret);
+ return NULL;
+ }
+
+ /* sanity check (this shouldn't happen) */
+ WARN_ON(args.args_count != 1);
+
+ mutex_lock(&hwspinlock_tree_lock);
+ list_for_each_entry(bank, &hwspinlock_devices, list)
+ if (bank->dev->of_node == args.np)
+ break;
+ mutex_unlock(&hwspinlock_tree_lock);
+ if (&bank->list == &hwspinlock_devices) {
+ pr_warn("%s: requested hwspinlock device %s is not registered\n",
+ __func__, args.np->full_name);
+ return NULL;
+ }
+
+ id = args.args[0];
+ if (id >= bank->num_locks) {
+ pr_warn("%s: requested lock %d is out of range [0, %d]\n",
+ __func__, id, bank->num_locks - 1);
+ return NULL;
+ }
+
+ id += bank->base_id;
+ return hwspin_lock_request_specific(id);
+}
+EXPORT_SYMBOL(of_hwspin_lock_request_specific);
+
+/**
* hwspin_lock_free() - free a specific hwspinlock
* @hwlock: the specific hwspinlock to free
*
@@ -1,7 +1,7 @@
/*
* Hardware spinlock public header
*
- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com
*
* Contact: Ohad Ben-Cohen <ohad@wizery.com>
*
@@ -26,6 +26,7 @@
#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
struct device;
+struct device_node;
struct hwspinlock;
struct hwspinlock_device;
struct hwspinlock_ops;
@@ -60,11 +61,14 @@ struct hwspinlock_pdata {
#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE)
+int of_hwspin_lock_get_num_locks(struct device_node *dn);
int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
const struct hwspinlock_ops *ops, int base_id, int num_locks);
int hwspin_lock_unregister(struct hwspinlock_device *bank);
struct hwspinlock *hwspin_lock_request(void);
struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
+struct hwspinlock *of_hwspin_lock_request_specific(struct device_node *np,
+ const char *propname, int index);
int hwspin_lock_free(struct hwspinlock *hwlock);
int hwspin_lock_get_id(struct hwspinlock *hwlock);
int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
@@ -80,9 +84,9 @@ void __hwspin_unlock(struct hwspinlock *, int, unsigned long *);
* code path get compiled away. This way, if CONFIG_HWSPINLOCK is not
* required on a given setup, users will still work.
*
- * The only exception is hwspin_lock_register/hwspin_lock_unregister, with which
- * we _do_ want users to fail (no point in registering hwspinlock instances if
- * the framework is not available).
+ * The only exception is hwspin_lock_register/hwspin_lock_unregister and
+ * associated OF helpers, with which we _do_ want users to fail (no point
+ * in registering hwspinlock instances if the framework is not available).
*
* Note: ERR_PTR(-ENODEV) will still be considered a success for NULL-checking
* users. Others, which care, can still check this with IS_ERR.
@@ -97,6 +101,13 @@ static inline struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
return ERR_PTR(-ENODEV);
}
+static inline
+struct hwspinlock *of_hwspin_lock_request_specific(struct device_node *np,
+ const char *propname, int index)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline int hwspin_lock_free(struct hwspinlock *hwlock)
{
return 0;
This patch adds the necessary documentation and OF helpers to represent a hwlock device and use/request locks in a device-tree build. All the platform-specific hwlock driver implementations need the number of locks and associated base id for registering the locks present within the device with the driver core. The number of locks is represented by 'hwlock-num-locks' property in DT bindings. A property for base id is not needed in DT binding, as it can be satisfied using a phandle + args specifier. OF helpers have been added to the driver core to read the common 'hwlock-num-locks' property, and to request a specific lock using the phandle + args specifier. The latter function is different from the existing non-DT function, in that the specifier is relative to the hwlock device instead of being a global lock id registered with the core. Signed-off-by: Suman Anna <s-anna@ti.com> --- .../devicetree/bindings/hwlock/hwlock.txt | 49 +++++++++++++ drivers/hwspinlock/hwspinlock_core.c | 85 +++++++++++++++++++++- include/linux/hwspinlock.h | 19 ++++- 3 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/hwlock/hwlock.txt