aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-07-03 17:52:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-07-03 17:52:25 -0400
commitd033ed9eeafc3bf33ce2de286ea2fb2c63e1c183 (patch)
tree21d877cc15c04c6717411a3d0fe948318291af04
parent6361c845ceab326a306412349fa6b125700b2cec (diff)
parentbd5717a4632cdecafe82d03de7dcb3b1876e2828 (diff)
Merge tag 'hwspinlock-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock
Pull hwspinlock updates from Ohad Ben-Cohen: - hwspinlock core DT support from Suman Anna - OMAP hwspinlock DT support from Suman Anna - QCOM hwspinlock DT support from Bjorn Andersson - a new CSR atlas7 hwspinlock driver from Wei Chen - CSR atlas7 hwspinlock DT binding document from Wei Chen - a tiny QCOM hwspinlock driver fix from Bjorn Andersson * tag 'hwspinlock-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock: hwspinlock: qcom: Correct msb in regmap_field DT: hwspinlock: add the CSR atlas7 hwspinlock bindings document hwspinlock: add a CSR atlas7 driver hwspinlock: qcom: Add support for Qualcomm HW Mutex block DT: hwspinlock: Add binding documentation for Qualcomm hwmutex hwspinlock/omap: add support for dt nodes Documentation: dt: add the omap hwspinlock bindings document hwspinlock/core: add device tree support Documentation: dt: add common bindings for hwspinlock
-rw-r--r--Documentation/devicetree/bindings/hwlock/hwlock.txt59
-rw-r--r--Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt26
-rw-r--r--Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt39
-rw-r--r--Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt28
-rw-r--r--Documentation/hwspinlock.txt10
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/hwspinlock.c60
-rw-r--r--drivers/hwspinlock/Kconfig24
-rw-r--r--drivers/hwspinlock/Makefile2
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c79
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c18
-rw-r--r--drivers/hwspinlock/qcom_hwspinlock.c181
-rw-r--r--drivers/hwspinlock/sirf_hwspinlock.c136
-rw-r--r--include/linux/hwspinlock.h7
15 files changed, 605 insertions, 68 deletions
diff --git a/Documentation/devicetree/bindings/hwlock/hwlock.txt b/Documentation/devicetree/bindings/hwlock/hwlock.txt
new file mode 100644
index 000000000000..085d1f5c916a
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwlock/hwlock.txt
@@ -0,0 +1,59 @@
1Generic hwlock bindings
2=======================
3
4Generic bindings that are common to all the hwlock platform specific driver
5implementations.
6
7Please also look through the individual platform specific hwlock binding
8documentations for identifying any additional properties specific to that
9platform.
10
11hwlock providers:
12=================
13
14Required properties:
15- #hwlock-cells: Specifies the number of cells needed to represent a
16 specific lock.
17
18hwlock users:
19=============
20
21Consumers that require specific hwlock(s) should specify them using the
22property "hwlocks", and an optional "hwlock-names" property.
23
24Required properties:
25- hwlocks: List of phandle to a hwlock provider node and an
26 associated hwlock args specifier as indicated by
27 #hwlock-cells. The list can have just a single hwlock
28 or multiple hwlocks, with each hwlock represented by
29 a phandle and a corresponding args specifier.
30
31Optional properties:
32- hwlock-names: List of hwlock name strings defined in the same order
33 as the hwlocks, with one name per hwlock. Consumers can
34 use the hwlock-names to match and get a specific hwlock.
35
36
371. Example of a node using a single specific hwlock:
38
39The following example has a node requesting a hwlock in the bank defined by
40the node hwlock1. hwlock1 is a hwlock provider with an argument specifier
41of length 1.
42
43 node {
44 ...
45 hwlocks = <&hwlock1 2>;
46 ...
47 };
48
492. Example of a node using multiple specific hwlocks:
50
51The following example has a node requesting two hwlocks, a hwlock within
52the hwlock device node 'hwlock1' with #hwlock-cells value of 1, and another
53hwlock within the hwlock device node 'hwlock2' with #hwlock-cells value of 2.
54
55 node {
56 ...
57 hwlocks = <&hwlock1 2>, <&hwlock2 0 3>;
58 ...
59 };
diff --git a/Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt
new file mode 100644
index 000000000000..2c9804f4f4ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt
@@ -0,0 +1,26 @@
1OMAP4+ HwSpinlock Driver
2========================
3
4Required properties:
5- compatible: Should be "ti,omap4-hwspinlock" for
6 OMAP44xx, OMAP54xx, AM33xx, AM43xx, DRA7xx SoCs
7- reg: Contains the hwspinlock module register address space
8 (base address and length)
9- ti,hwmods: Name of the hwmod associated with the hwspinlock device
10- #hwlock-cells: Should be 1. The OMAP hwspinlock users will use a
11 0-indexed relative hwlock number as the argument
12 specifier value for requesting a specific hwspinlock
13 within a hwspinlock bank.
14
15Please look at the generic hwlock binding for usage information for consumers,
16"Documentation/devicetree/bindings/hwlock/hwlock.txt"
17
18Example:
19
20/* OMAP4 */
21hwspinlock: spinlock@4a0f6000 {
22 compatible = "ti,omap4-hwspinlock";
23 reg = <0x4a0f6000 0x1000>;
24 ti,hwmods = "spinlock";
25 #hwlock-cells = <1>;
26};
diff --git a/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt
new file mode 100644
index 000000000000..4563f524556b
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt
@@ -0,0 +1,39 @@
1Qualcomm Hardware Mutex Block:
2
3The hardware block provides mutexes utilized between different processors on
4the SoC as part of the communication protocol used by these processors.
5
6- compatible:
7 Usage: required
8 Value type: <string>
9 Definition: must be one of:
10 "qcom,sfpb-mutex",
11 "qcom,tcsr-mutex"
12
13- syscon:
14 Usage: required
15 Value type: <prop-encoded-array>
16 Definition: one cell containing:
17 syscon phandle
18 offset of the hwmutex block within the syscon
19 stride of the hwmutex registers
20
21- #hwlock-cells:
22 Usage: required
23 Value type: <u32>
24 Definition: must be 1, the specified cell represent the lock id
25 (hwlock standard property, see hwlock.txt)
26
27Example:
28
29 tcsr_mutex_block: syscon@fd484000 {
30 compatible = "syscon";
31 reg = <0xfd484000 0x2000>;
32 };
33
34 hwlock@fd484000 {
35 compatible = "qcom,tcsr-mutex";
36 syscon = <&tcsr_mutex_block 0 0x80>;
37
38 #hwlock-cells = <1>;
39 };
diff --git a/Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt
new file mode 100644
index 000000000000..9bb1240a68e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt
@@ -0,0 +1,28 @@
1SIRF Hardware spinlock device Binding
2-----------------------------------------------
3
4Required properties :
5- compatible : shall contain only one of the following:
6 "sirf,hwspinlock"
7
8- reg : the register address of hwspinlock
9
10- #hwlock-cells : hwlock users only use the hwlock id to represent a specific
11 hwlock, so the number of cells should be <1> here.
12
13Please look at the generic hwlock binding for usage information for consumers,
14"Documentation/devicetree/bindings/hwlock/hwlock.txt"
15
16Example of hwlock provider:
17 hwlock {
18 compatible = "sirf,hwspinlock";
19 reg = <0x13240000 0x00010000>;
20 #hwlock-cells = <1>;
21 };
22
23Example of hwlock users:
24 node {
25 ...
26 hwlocks = <&hwlock 2>;
27 ...
28 };
diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
index 62f7d4ea6e26..61c1ee98e59f 100644
--- a/Documentation/hwspinlock.txt
+++ b/Documentation/hwspinlock.txt
@@ -48,6 +48,16 @@ independent, drivers.
48 ids for predefined purposes. 48 ids for predefined purposes.
49 Should be called from a process context (might sleep). 49 Should be called from a process context (might sleep).
50 50
51 int of_hwspin_lock_get_id(struct device_node *np, int index);
52 - retrieve the global lock id for an OF phandle-based specific lock.
53 This function provides a means for DT users of a hwspinlock module
54 to get the global lock id of a specific hwspinlock, so that it can
55 be requested using the normal hwspin_lock_request_specific() API.
56 The function returns a lock id number on success, -EPROBE_DEFER if
57 the hwspinlock device is not yet registered with the core, or other
58 error values.
59 Should be called from a process context (might sleep).
60
51 int hwspin_lock_free(struct hwspinlock *hwlock); 61 int hwspin_lock_free(struct hwspinlock *hwlock);
52 - free a previously-assigned hwspinlock; returns 0 on success, or an 62 - free a previously-assigned hwspinlock; returns 0 on success, or an
53 appropriate error code on failure (e.g. -EINVAL if the hwspinlock 63 appropriate error code on failure (e.g. -EINVAL if the hwspinlock
diff --git a/MAINTAINERS b/MAINTAINERS
index 86ea2084bc58..e23ff1cbd12b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7364,7 +7364,6 @@ M: Ohad Ben-Cohen <ohad@wizery.com>
7364L: linux-omap@vger.kernel.org 7364L: linux-omap@vger.kernel.org
7365S: Maintained 7365S: Maintained
7366F: drivers/hwspinlock/omap_hwspinlock.c 7366F: drivers/hwspinlock/omap_hwspinlock.c
7367F: arch/arm/mach-omap2/hwspinlock.c
7368 7367
7369OMAP MMC SUPPORT 7368OMAP MMC SUPPORT
7370M: Jarkko Lavinen <jarkko.lavinen@nokia.com> 7369M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index f1a68c63dc99..903c85be2897 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -274,8 +274,5 @@ obj-y += $(nand-m) $(nand-y)
274 274
275smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o 275smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
276obj-y += $(smsc911x-m) $(smsc911x-y) 276obj-y += $(smsc911x-m) $(smsc911x-y)
277ifneq ($(CONFIG_HWSPINLOCK_OMAP),)
278obj-y += hwspinlock.o
279endif
280 277
281obj-y += common-board-devices.o twl-common.o dss-common.o 278obj-y += common-board-devices.o twl-common.o dss-common.o
diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c
deleted file mode 100644
index ef175acaeaa2..000000000000
--- a/arch/arm/mach-omap2/hwspinlock.c
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 * OMAP hardware spinlock device initialization
3 *
4 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
5 *
6 * Contact: Simon Que <sque@ti.com>
7 * Hari Kanigeri <h-kanigeri2@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/err.h>
22#include <linux/hwspinlock.h>
23
24#include "soc.h"
25#include "omap_hwmod.h"
26#include "omap_device.h"
27
28static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = {
29 .base_id = 0,
30};
31
32static int __init hwspinlocks_init(void)
33{
34 int retval = 0;
35 struct omap_hwmod *oh;
36 struct platform_device *pdev;
37 const char *oh_name = "spinlock";
38 const char *dev_name = "omap_hwspinlock";
39
40 /*
41 * Hwmod lookup will fail in case our platform doesn't support the
42 * hardware spinlock module, so it is safe to run this initcall
43 * on all omaps
44 */
45 oh = omap_hwmod_lookup(oh_name);
46 if (oh == NULL)
47 return -EINVAL;
48
49 pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata,
50 sizeof(struct hwspinlock_pdata));
51 if (IS_ERR(pdev)) {
52 pr_err("Can't build omap_device for %s:%s\n", dev_name,
53 oh_name);
54 retval = PTR_ERR(pdev);
55 }
56
57 return retval;
58}
59/* early board code might need to reserve specific hwspinlock instances */
60omap_postcore_initcall(hwspinlocks_init);
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
index 3612cb5b30b2..73a401662853 100644
--- a/drivers/hwspinlock/Kconfig
+++ b/drivers/hwspinlock/Kconfig
@@ -18,6 +18,30 @@ config HWSPINLOCK_OMAP
18 18
19 If unsure, say N. 19 If unsure, say N.
20 20
21config HWSPINLOCK_QCOM
22 tristate "Qualcomm Hardware Spinlock device"
23 depends on ARCH_QCOM
24 select HWSPINLOCK
25 select MFD_SYSCON
26 help
27 Say y here to support the Qualcomm Hardware Mutex functionality, which
28 provides a synchronisation mechanism for the various processors on
29 the SoC.
30
31 If unsure, say N.
32
33config HWSPINLOCK_SIRF
34 tristate "SIRF Hardware Spinlock device"
35 depends on ARCH_SIRF
36 select HWSPINLOCK
37 help
38 Say y here to support the SIRF Hardware Spinlock device, which
39 provides a synchronisation mechanism for the various processors
40 on the SoC.
41
42 It's safe to say n here if you're not interested in SIRF hardware
43 spinlock or just want a bare minimum kernel.
44
21config HSEM_U8500 45config HSEM_U8500
22 tristate "STE Hardware Semaphore functionality" 46 tristate "STE Hardware Semaphore functionality"
23 depends on ARCH_U8500 47 depends on ARCH_U8500
diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile
index 93eb64b66486..6b59cb5a4f3a 100644
--- a/drivers/hwspinlock/Makefile
+++ b/drivers/hwspinlock/Makefile
@@ -4,4 +4,6 @@
4 4
5obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o 5obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
6obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o 6obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
7obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o
8obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o
7obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o 9obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 461a0d739d75..52f708bcf77f 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -27,6 +27,7 @@
27#include <linux/hwspinlock.h> 27#include <linux/hwspinlock.h>
28#include <linux/pm_runtime.h> 28#include <linux/pm_runtime.h>
29#include <linux/mutex.h> 29#include <linux/mutex.h>
30#include <linux/of.h>
30 31
31#include "hwspinlock_internal.h" 32#include "hwspinlock_internal.h"
32 33
@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
257} 258}
258EXPORT_SYMBOL_GPL(__hwspin_unlock); 259EXPORT_SYMBOL_GPL(__hwspin_unlock);
259 260
261/**
262 * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
263 * @bank: the hwspinlock device bank
264 * @hwlock_spec: hwlock specifier as found in the device tree
265 *
266 * This is a simple translation function, suitable for hwspinlock platform
267 * drivers that only has a lock specifier length of 1.
268 *
269 * Returns a relative index of the lock within a specified bank on success,
270 * or -EINVAL on invalid specifier cell count.
271 */
272static inline int
273of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
274{
275 if (WARN_ON(hwlock_spec->args_count != 1))
276 return -EINVAL;
277
278 return hwlock_spec->args[0];
279}
280
281/**
282 * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock
283 * @np: device node from which to request the specific hwlock
284 * @index: index of the hwlock in the list of values
285 *
286 * This function provides a means for DT users of the hwspinlock module to
287 * get the global lock id of a specific hwspinlock using the phandle of the
288 * hwspinlock device, so that it can be requested using the normal
289 * hwspin_lock_request_specific() API.
290 *
291 * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock
292 * device is not yet registered, -EINVAL on invalid args specifier value or an
293 * appropriate error as returned from the OF parsing of the DT client node.
294 */
295int of_hwspin_lock_get_id(struct device_node *np, int index)
296{
297 struct of_phandle_args args;
298 struct hwspinlock *hwlock;
299 struct radix_tree_iter iter;
300 void **slot;
301 int id;
302 int ret;
303
304 ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index,
305 &args);
306 if (ret)
307 return ret;
308
309 /* Find the hwspinlock device: we need its base_id */
310 ret = -EPROBE_DEFER;
311 rcu_read_lock();
312 radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) {
313 hwlock = radix_tree_deref_slot(slot);
314 if (unlikely(!hwlock))
315 continue;
316
317 if (hwlock->bank->dev->of_node == args.np) {
318 ret = 0;
319 break;
320 }
321 }
322 rcu_read_unlock();
323 if (ret < 0)
324 goto out;
325
326 id = of_hwspin_lock_simple_xlate(&args);
327 if (id < 0 || id >= hwlock->bank->num_locks) {
328 ret = -EINVAL;
329 goto out;
330 }
331 id += hwlock->bank->base_id;
332
333out:
334 of_node_put(args.np);
335 return ret ? ret : id;
336}
337EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
338
260static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) 339static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
261{ 340{
262 struct hwspinlock *tmp; 341 struct hwspinlock *tmp;
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index 47a275c6ece1..ad2f8cac8487 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * OMAP hardware spinlock driver 2 * OMAP hardware spinlock driver
3 * 3 *
4 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com 4 * Copyright (C) 2010-2015 Texas Instruments Incorporated - http://www.ti.com
5 * 5 *
6 * Contact: Simon Que <sque@ti.com> 6 * Contact: Simon Que <sque@ti.com>
7 * Hari Kanigeri <h-kanigeri2@ti.com> 7 * Hari Kanigeri <h-kanigeri2@ti.com>
@@ -27,6 +27,7 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/spinlock.h> 28#include <linux/spinlock.h>
29#include <linux/hwspinlock.h> 29#include <linux/hwspinlock.h>
30#include <linux/of.h>
30#include <linux/platform_device.h> 31#include <linux/platform_device.h>
31 32
32#include "hwspinlock_internal.h" 33#include "hwspinlock_internal.h"
@@ -80,14 +81,16 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = {
80 81
81static int omap_hwspinlock_probe(struct platform_device *pdev) 82static int omap_hwspinlock_probe(struct platform_device *pdev)
82{ 83{
83 struct hwspinlock_pdata *pdata = pdev->dev.platform_data; 84 struct device_node *node = pdev->dev.of_node;
84 struct hwspinlock_device *bank; 85 struct hwspinlock_device *bank;
85 struct hwspinlock *hwlock; 86 struct hwspinlock *hwlock;
86 struct resource *res; 87 struct resource *res;
87 void __iomem *io_base; 88 void __iomem *io_base;
88 int num_locks, i, ret; 89 int num_locks, i, ret;
90 /* Only a single hwspinlock block device is supported */
91 int base_id = 0;
89 92
90 if (!pdata) 93 if (!node)
91 return -ENODEV; 94 return -ENODEV;
92 95
93 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 96 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -141,7 +144,7 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
141 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i; 144 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
142 145
143 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops, 146 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
144 pdata->base_id, num_locks); 147 base_id, num_locks);
145 if (ret) 148 if (ret)
146 goto reg_fail; 149 goto reg_fail;
147 150
@@ -174,11 +177,18 @@ static int omap_hwspinlock_remove(struct platform_device *pdev)
174 return 0; 177 return 0;
175} 178}
176 179
180static const struct of_device_id omap_hwspinlock_of_match[] = {
181 { .compatible = "ti,omap4-hwspinlock", },
182 { /* end */ },
183};
184MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match);
185
177static struct platform_driver omap_hwspinlock_driver = { 186static struct platform_driver omap_hwspinlock_driver = {
178 .probe = omap_hwspinlock_probe, 187 .probe = omap_hwspinlock_probe,
179 .remove = omap_hwspinlock_remove, 188 .remove = omap_hwspinlock_remove,
180 .driver = { 189 .driver = {
181 .name = "omap_hwspinlock", 190 .name = "omap_hwspinlock",
191 .of_match_table = of_match_ptr(omap_hwspinlock_of_match),
182 }, 192 },
183}; 193};
184 194
diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c
new file mode 100644
index 000000000000..c752447fbac7
--- /dev/null
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -0,0 +1,181 @@
1/*
2 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2015, Sony Mobile Communications AB
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/hwspinlock.h>
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/mfd/syscon.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_device.h>
22#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
24#include <linux/regmap.h>
25
26#include "hwspinlock_internal.h"
27
28#define QCOM_MUTEX_APPS_PROC_ID 1
29#define QCOM_MUTEX_NUM_LOCKS 32
30
31static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
32{
33 struct regmap_field *field = lock->priv;
34 u32 lock_owner;
35 int ret;
36
37 ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
38 if (ret)
39 return ret;
40
41 ret = regmap_field_read(field, &lock_owner);
42 if (ret)
43 return ret;
44
45 return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
46}
47
48static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
49{
50 struct regmap_field *field = lock->priv;
51 u32 lock_owner;
52 int ret;
53
54 ret = regmap_field_read(field, &lock_owner);
55 if (ret) {
56 pr_err("%s: unable to query spinlock owner\n", __func__);
57 return;
58 }
59
60 if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) {
61 pr_err("%s: spinlock not owned by us (actual owner is %d)\n",
62 __func__, lock_owner);
63 }
64
65 ret = regmap_field_write(field, 0);
66 if (ret)
67 pr_err("%s: failed to unlock spinlock\n", __func__);
68}
69
70static const struct hwspinlock_ops qcom_hwspinlock_ops = {
71 .trylock = qcom_hwspinlock_trylock,
72 .unlock = qcom_hwspinlock_unlock,
73};
74
75static const struct of_device_id qcom_hwspinlock_of_match[] = {
76 { .compatible = "qcom,sfpb-mutex" },
77 { .compatible = "qcom,tcsr-mutex" },
78 { }
79};
80MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match);
81
82static int qcom_hwspinlock_probe(struct platform_device *pdev)
83{
84 struct hwspinlock_device *bank;
85 struct device_node *syscon;
86 struct reg_field field;
87 struct regmap *regmap;
88 size_t array_size;
89 u32 stride;
90 u32 base;
91 int ret;
92 int i;
93
94 syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0);
95 if (!syscon) {
96 dev_err(&pdev->dev, "no syscon property\n");
97 return -ENODEV;
98 }
99
100 regmap = syscon_node_to_regmap(syscon);
101 if (IS_ERR(regmap))
102 return PTR_ERR(regmap);
103
104 ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base);
105 if (ret < 0) {
106 dev_err(&pdev->dev, "no offset in syscon\n");
107 return -EINVAL;
108 }
109
110 ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride);
111 if (ret < 0) {
112 dev_err(&pdev->dev, "no stride syscon\n");
113 return -EINVAL;
114 }
115
116 array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
117 bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL);
118 if (!bank)
119 return -ENOMEM;
120
121 platform_set_drvdata(pdev, bank);
122
123 for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) {
124 field.reg = base + i * stride;
125 field.lsb = 0;
126 field.msb = 31;
127
128 bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev,
129 regmap, field);
130 }
131
132 pm_runtime_enable(&pdev->dev);
133
134 ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops,
135 0, QCOM_MUTEX_NUM_LOCKS);
136 if (ret)
137 pm_runtime_disable(&pdev->dev);
138
139 return ret;
140}
141
142static int qcom_hwspinlock_remove(struct platform_device *pdev)
143{
144 struct hwspinlock_device *bank = platform_get_drvdata(pdev);
145 int ret;
146
147 ret = hwspin_lock_unregister(bank);
148 if (ret) {
149 dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
150 return ret;
151 }
152
153 pm_runtime_disable(&pdev->dev);
154
155 return 0;
156}
157
158static struct platform_driver qcom_hwspinlock_driver = {
159 .probe = qcom_hwspinlock_probe,
160 .remove = qcom_hwspinlock_remove,
161 .driver = {
162 .name = "qcom_hwspinlock",
163 .of_match_table = qcom_hwspinlock_of_match,
164 },
165};
166
167static int __init qcom_hwspinlock_init(void)
168{
169 return platform_driver_register(&qcom_hwspinlock_driver);
170}
171/* board init code might need to reserve hwspinlocks for predefined purposes */
172postcore_initcall(qcom_hwspinlock_init);
173
174static void __exit qcom_hwspinlock_exit(void)
175{
176 platform_driver_unregister(&qcom_hwspinlock_driver);
177}
178module_exit(qcom_hwspinlock_exit);
179
180MODULE_LICENSE("GPL v2");
181MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs");
diff --git a/drivers/hwspinlock/sirf_hwspinlock.c b/drivers/hwspinlock/sirf_hwspinlock.c
new file mode 100644
index 000000000000..16018544d431
--- /dev/null
+++ b/drivers/hwspinlock/sirf_hwspinlock.c
@@ -0,0 +1,136 @@
1/*
2 * SIRF hardware spinlock driver
3 *
4 * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2.
7 */
8
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/device.h>
12#include <linux/io.h>
13#include <linux/pm_runtime.h>
14#include <linux/slab.h>
15#include <linux/spinlock.h>
16#include <linux/hwspinlock.h>
17#include <linux/platform_device.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20
21#include "hwspinlock_internal.h"
22
23struct sirf_hwspinlock {
24 void __iomem *io_base;
25 struct hwspinlock_device bank;
26};
27
28/* Number of Hardware Spinlocks*/
29#define HW_SPINLOCK_NUMBER 30
30
31/* Hardware spinlock register offsets */
32#define HW_SPINLOCK_BASE 0x404
33#define HW_SPINLOCK_OFFSET(x) (HW_SPINLOCK_BASE + 0x4 * (x))
34
35static int sirf_hwspinlock_trylock(struct hwspinlock *lock)
36{
37 void __iomem *lock_addr = lock->priv;
38
39 /* attempt to acquire the lock by reading value == 1 from it */
40 return !!readl(lock_addr);
41}
42
43static void sirf_hwspinlock_unlock(struct hwspinlock *lock)
44{
45 void __iomem *lock_addr = lock->priv;
46
47 /* release the lock by writing 0 to it */
48 writel(0, lock_addr);
49}
50
51static const struct hwspinlock_ops sirf_hwspinlock_ops = {
52 .trylock = sirf_hwspinlock_trylock,
53 .unlock = sirf_hwspinlock_unlock,
54};
55
56static int sirf_hwspinlock_probe(struct platform_device *pdev)
57{
58 struct sirf_hwspinlock *hwspin;
59 struct hwspinlock *hwlock;
60 int idx, ret;
61
62 if (!pdev->dev.of_node)
63 return -ENODEV;
64
65 hwspin = devm_kzalloc(&pdev->dev, sizeof(*hwspin) +
66 sizeof(*hwlock) * HW_SPINLOCK_NUMBER, GFP_KERNEL);
67 if (!hwspin)
68 return -ENOMEM;
69
70 /* retrieve io base */
71 hwspin->io_base = of_iomap(pdev->dev.of_node, 0);
72 if (!hwspin->io_base)
73 return -ENOMEM;
74
75 for (idx = 0; idx < HW_SPINLOCK_NUMBER; idx++) {
76 hwlock = &hwspin->bank.lock[idx];
77 hwlock->priv = hwspin->io_base + HW_SPINLOCK_OFFSET(idx);
78 }
79
80 platform_set_drvdata(pdev, hwspin);
81
82 pm_runtime_enable(&pdev->dev);
83
84 ret = hwspin_lock_register(&hwspin->bank, &pdev->dev,
85 &sirf_hwspinlock_ops, 0,
86 HW_SPINLOCK_NUMBER);
87 if (ret)
88 goto reg_failed;
89
90 return 0;
91
92reg_failed:
93 pm_runtime_disable(&pdev->dev);
94 iounmap(hwspin->io_base);
95
96 return ret;
97}
98
99static int sirf_hwspinlock_remove(struct platform_device *pdev)
100{
101 struct sirf_hwspinlock *hwspin = platform_get_drvdata(pdev);
102 int ret;
103
104 ret = hwspin_lock_unregister(&hwspin->bank);
105 if (ret) {
106 dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
107 return ret;
108 }
109
110 pm_runtime_disable(&pdev->dev);
111
112 iounmap(hwspin->io_base);
113
114 return 0;
115}
116
117static const struct of_device_id sirf_hwpinlock_ids[] = {
118 { .compatible = "sirf,hwspinlock", },
119 {},
120};
121MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids);
122
123static struct platform_driver sirf_hwspinlock_driver = {
124 .probe = sirf_hwspinlock_probe,
125 .remove = sirf_hwspinlock_remove,
126 .driver = {
127 .name = "atlas7_hwspinlock",
128 .of_match_table = of_match_ptr(sirf_hwpinlock_ids),
129 },
130};
131
132module_platform_driver(sirf_hwspinlock_driver);
133
134MODULE_LICENSE("GPL v2");
135MODULE_DESCRIPTION("SIRF Hardware spinlock driver");
136MODULE_AUTHOR("Wei Chen <wei.chen@csr.com>");
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
index 3343298e40e8..859d673d98c8 100644
--- a/include/linux/hwspinlock.h
+++ b/include/linux/hwspinlock.h
@@ -26,6 +26,7 @@
26#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ 26#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
27 27
28struct device; 28struct device;
29struct device_node;
29struct hwspinlock; 30struct hwspinlock;
30struct hwspinlock_device; 31struct hwspinlock_device;
31struct hwspinlock_ops; 32struct hwspinlock_ops;
@@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank);
66struct hwspinlock *hwspin_lock_request(void); 67struct hwspinlock *hwspin_lock_request(void);
67struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 68struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
68int hwspin_lock_free(struct hwspinlock *hwlock); 69int hwspin_lock_free(struct hwspinlock *hwlock);
70int of_hwspin_lock_get_id(struct device_node *np, int index);
69int hwspin_lock_get_id(struct hwspinlock *hwlock); 71int hwspin_lock_get_id(struct hwspinlock *hwlock);
70int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, 72int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
71 unsigned long *); 73 unsigned long *);
@@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
120{ 122{
121} 123}
122 124
125static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
126{
127 return 0;
128}
129
123static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) 130static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
124{ 131{
125 return 0; 132 return 0;