hwspinlock/core: add device tree support
This patch adds a new OF-friendly API of_hwspin_lock_get_id() for hwspinlock clients to use/request locks from a hwspinlock device instantiated through a device-tree blob. This new API can be used by hwspinlock clients to get the id for a specific lock using the phandle + args specifier, so that it can be requested using the available hwspin_lock_request_specific() API. Signed-off-by: Suman Anna <s-anna@ti.com> Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> [small comment clarification] Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
This commit is contained in:
parent
0ce8cf2f31
commit
fb7737e949
3 changed files with 96 additions and 0 deletions
|
@ -48,6 +48,16 @@ independent, drivers.
|
||||||
ids for predefined purposes.
|
ids for predefined purposes.
|
||||||
Should be called from a process context (might sleep).
|
Should be called from a process context (might sleep).
|
||||||
|
|
||||||
|
int of_hwspin_lock_get_id(struct device_node *np, int index);
|
||||||
|
- retrieve the global lock id for an OF phandle-based specific lock.
|
||||||
|
This function provides a means for DT users of a hwspinlock module
|
||||||
|
to get the global lock id of a specific hwspinlock, so that it can
|
||||||
|
be requested using the normal hwspin_lock_request_specific() API.
|
||||||
|
The function returns a lock id number on success, -EPROBE_DEFER if
|
||||||
|
the hwspinlock device is not yet registered with the core, or other
|
||||||
|
error values.
|
||||||
|
Should be called from a process context (might sleep).
|
||||||
|
|
||||||
int hwspin_lock_free(struct hwspinlock *hwlock);
|
int hwspin_lock_free(struct hwspinlock *hwlock);
|
||||||
- free a previously-assigned hwspinlock; returns 0 on success, or an
|
- free a previously-assigned hwspinlock; returns 0 on success, or an
|
||||||
appropriate error code on failure (e.g. -EINVAL if the hwspinlock
|
appropriate error code on failure (e.g. -EINVAL if the hwspinlock
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/hwspinlock.h>
|
#include <linux/hwspinlock.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
#include "hwspinlock_internal.h"
|
#include "hwspinlock_internal.h"
|
||||||
|
|
||||||
|
@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__hwspin_unlock);
|
EXPORT_SYMBOL_GPL(__hwspin_unlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
|
||||||
|
* @bank: the hwspinlock device bank
|
||||||
|
* @hwlock_spec: hwlock specifier as found in the device tree
|
||||||
|
*
|
||||||
|
* This is a simple translation function, suitable for hwspinlock platform
|
||||||
|
* drivers that only has a lock specifier length of 1.
|
||||||
|
*
|
||||||
|
* Returns a relative index of the lock within a specified bank on success,
|
||||||
|
* or -EINVAL on invalid specifier cell count.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
|
||||||
|
{
|
||||||
|
if (WARN_ON(hwlock_spec->args_count != 1))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return hwlock_spec->args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock
|
||||||
|
* @np: device node from which to request the specific hwlock
|
||||||
|
* @index: index of the hwlock in the list of values
|
||||||
|
*
|
||||||
|
* This function provides a means for DT users of the hwspinlock module to
|
||||||
|
* get the global lock id of a specific hwspinlock using the phandle of the
|
||||||
|
* hwspinlock device, so that it can be requested using the normal
|
||||||
|
* hwspin_lock_request_specific() API.
|
||||||
|
*
|
||||||
|
* Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock
|
||||||
|
* device is not yet registered, -EINVAL on invalid args specifier value or an
|
||||||
|
* appropriate error as returned from the OF parsing of the DT client node.
|
||||||
|
*/
|
||||||
|
int of_hwspin_lock_get_id(struct device_node *np, int index)
|
||||||
|
{
|
||||||
|
struct of_phandle_args args;
|
||||||
|
struct hwspinlock *hwlock;
|
||||||
|
struct radix_tree_iter iter;
|
||||||
|
void **slot;
|
||||||
|
int id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index,
|
||||||
|
&args);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Find the hwspinlock device: we need its base_id */
|
||||||
|
ret = -EPROBE_DEFER;
|
||||||
|
rcu_read_lock();
|
||||||
|
radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) {
|
||||||
|
hwlock = radix_tree_deref_slot(slot);
|
||||||
|
if (unlikely(!hwlock))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hwlock->bank->dev->of_node == args.np) {
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
id = of_hwspin_lock_simple_xlate(&args);
|
||||||
|
if (id < 0 || id >= hwlock->bank->num_locks) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
id += hwlock->bank->base_id;
|
||||||
|
|
||||||
|
out:
|
||||||
|
of_node_put(args.np);
|
||||||
|
return ret ? ret : id;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
|
||||||
|
|
||||||
static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
|
static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
|
||||||
{
|
{
|
||||||
struct hwspinlock *tmp;
|
struct hwspinlock *tmp;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
|
#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
|
struct device_node;
|
||||||
struct hwspinlock;
|
struct hwspinlock;
|
||||||
struct hwspinlock_device;
|
struct hwspinlock_device;
|
||||||
struct hwspinlock_ops;
|
struct hwspinlock_ops;
|
||||||
|
@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank);
|
||||||
struct hwspinlock *hwspin_lock_request(void);
|
struct hwspinlock *hwspin_lock_request(void);
|
||||||
struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
|
struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
|
||||||
int hwspin_lock_free(struct hwspinlock *hwlock);
|
int hwspin_lock_free(struct hwspinlock *hwlock);
|
||||||
|
int of_hwspin_lock_get_id(struct device_node *np, int index);
|
||||||
int hwspin_lock_get_id(struct hwspinlock *hwlock);
|
int hwspin_lock_get_id(struct hwspinlock *hwlock);
|
||||||
int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
|
int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
|
||||||
unsigned long *);
|
unsigned long *);
|
||||||
|
@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
|
static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue