History

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

Linus Torvalds committed 11 years ago

Commit d033ed92 parents 6361c84 bd5717a15 files · +605 −68Browse files

Unified · Split

15 files
  1. Documentation/devicetree/bindings/hwlock/hwlock.txt +59 −0
  2. Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt +26 −0
  3. Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt +39 −0
  4. Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt +28 −0
  5. Documentation/hwspinlock.txt +10 −0
  6. MAINTAINERS +0 −1
  7. arch/arm/mach-omap2/Makefile +0 −3
  8. arch/arm/mach-omap2/hwspinlock.c +0 −60
  9. drivers/hwspinlock/Kconfig +24 −0
  10. drivers/hwspinlock/Makefile +2 −0
  11. drivers/hwspinlock/hwspinlock_core.c +79 −0
  12. drivers/hwspinlock/omap_hwspinlock.c +14 −4
  13. drivers/hwspinlock/qcom_hwspinlock.c +181 −0
  14. drivers/hwspinlock/sirf_hwspinlock.c +136 −0
  15. include/linux/hwspinlock.h +7 −0
Documentation/devicetree/bindings/hwlock/hwlock.txt+59−0
@@ -0,0 +1,59 @@
1+Generic hwlock bindings
2+=======================
3+
4+Generic bindings that are common to all the hwlock platform specific driver
5+implementations.
6+
7+Please also look through the individual platform specific hwlock binding
8+documentations for identifying any additional properties specific to that
9+platform.
10+
11+hwlock providers:
12+=================
13+
14+Required properties:
15+- #hwlock-cells: Specifies the number of cells needed to represent a
16+ specific lock.
17+
18+hwlock users:
19+=============
20+
21+Consumers that require specific hwlock(s) should specify them using the
22+property "hwlocks", and an optional "hwlock-names" property.
23+
24+Required 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+
31+Optional 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+
37+1. Example of a node using a single specific hwlock:
38+
39+The following example has a node requesting a hwlock in the bank defined by
40+the node hwlock1. hwlock1 is a hwlock provider with an argument specifier
41+of length 1.
42+
43+ node {
44+ ...
45+ hwlocks = <&hwlock1 2>;
46+ ...
47+ };
48+
49+2. Example of a node using multiple specific hwlocks:
50+
51+The following example has a node requesting two hwlocks, a hwlock within
52+the hwlock device node 'hwlock1' with #hwlock-cells value of 1, and another
53+hwlock 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+ };
Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt+26−0
@@ -0,0 +1,26 @@
1+OMAP4+ HwSpinlock Driver
2+========================
3+
4+Required 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+
15+Please look at the generic hwlock binding for usage information for consumers,
16+"Documentation/devicetree/bindings/hwlock/hwlock.txt"
17+
18+Example:
19+
20+/* OMAP4 */
21+hwspinlock: spinlock@4a0f6000 {
22+ compatible = "ti,omap4-hwspinlock";
23+ reg = <0x4a0f6000 0x1000>;
24+ ti,hwmods = "spinlock";
25+ #hwlock-cells = <1>;
26+};
Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt+39−0
@@ -0,0 +1,39 @@
1+Qualcomm Hardware Mutex Block:
2+
3+The hardware block provides mutexes utilized between different processors on
4+the 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+
27+Example:
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+ };
Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt+28−0
@@ -0,0 +1,28 @@
1+SIRF Hardware spinlock device Binding
2+-----------------------------------------------
3+
4+Required 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+
13+Please look at the generic hwlock binding for usage information for consumers,
14+"Documentation/devicetree/bindings/hwlock/hwlock.txt"
15+
16+Example of hwlock provider:
17+ hwlock {
18+ compatible = "sirf,hwspinlock";
19+ reg = <0x13240000 0x00010000>;
20+ #hwlock-cells = <1>;
21+ };
22+
23+Example of hwlock users:
24+ node {
25+ ...
26+ hwlocks = <&hwlock 2>;
27+ ...
28+ };
Documentation/hwspinlock.txt+10−0
@@ -48,6 +48,16 @@ independent, drivers. · 47 unmodified lines
4848 ids for predefined purposes.
4949 Should be called from a process context (might sleep).
5050
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+
5161 int hwspin_lock_free(struct hwspinlock *hwlock);
5262 - free a previously-assigned hwspinlock; returns 0 on success, or an
5363 appropriate error code on failure (e.g. -EINVAL if the hwspinlock
MAINTAINERS+0−1
@@ -7364,7 +7364,6 @@ M: Ohad Ben-Cohen <ohad@wizery.com> · 7363 unmodified lines
73647364 L: linux-omap@vger.kernel.org
73657365 S: Maintained
73667366 F: drivers/hwspinlock/omap_hwspinlock.c
7367−F: arch/arm/mach-omap2/hwspinlock.c
73687367
73697368 OMAP MMC SUPPORT
73707369 M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
arch/arm/mach-omap2/Makefile+0−3
@@ -274,8 +274,5 @@ obj-y += $(nand-m) $(nand-y) · 273 unmodified lines
274274
275275 smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
276276 obj-y += $(smsc911x-m) $(smsc911x-y)
277−ifneq ($(CONFIG_HWSPINLOCK_OMAP),)
278−obj-y += hwspinlock.o
279−endif
280277
281278 obj-y += common-board-devices.o twl-common.o dss-common.o
arch/arm/mach-omap2/hwspinlock.c+0−60
@@ -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−
28−static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = {
29− .base_id = 0,
30−};
31−
32−static 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 */
60−omap_postcore_initcall(hwspinlocks_init);
drivers/hwspinlock/Kconfig+24−0
@@ -18,6 +18,30 @@ config HWSPINLOCK_OMAP · 17 unmodified lines
1818
1919 If unsure, say N.
2020
21+config 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+
33+config 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+
2145 config HSEM_U8500
2246 tristate "STE Hardware Semaphore functionality"
2347 depends on ARCH_U8500
drivers/hwspinlock/Makefile+2−0
@@ -4,4 +4,6 @@ · 3 unmodified lines
44
55 obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
66 obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
7+obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o
8+obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o
79 obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
drivers/hwspinlock/hwspinlock_core.c+79−0
@@ -27,6 +27,7 @@ · 26 unmodified lines
2727 #include <linux/hwspinlock.h>
2828 #include <linux/pm_runtime.h>
2929 #include <linux/mutex.h>
30+#include <linux/of.h>
3031
3132 #include "hwspinlock_internal.h"
3233
@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) · 224 unmodified lines
257258 }
258259 EXPORT_SYMBOL_GPL(__hwspin_unlock);
259260
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+ */
272+static inline int
273+of_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+ */
295+int 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+
333+out:
334+ of_node_put(args.np);
335+ return ret ? ret : id;
336+}
337+EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
338+
260339 static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
261340 {
262341 struct hwspinlock *tmp;
drivers/hwspinlock/omap_hwspinlock.c+14−4
@@ -1,7 +1,7 @@
11 /*
22 * OMAP hardware spinlock driver
33 *
4− * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
4+ * Copyright (C) 2010-2015 Texas Instruments Incorporated - http://www.ti.com
55 *
66 * Contact: Simon Que <sque@ti.com>
77 * Hari Kanigeri <h-kanigeri2@ti.com>
@@ -27,6 +27,7 @@ · 19 unmodified lines
2727 #include <linux/slab.h>
2828 #include <linux/spinlock.h>
2929 #include <linux/hwspinlock.h>
30+#include <linux/of.h>
3031 #include <linux/platform_device.h>
3132
3233 #include "hwspinlock_internal.h"
@@ -80,14 +81,16 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = { · 47 unmodified lines
8081
8182 static int omap_hwspinlock_probe(struct platform_device *pdev)
8283 {
83− struct hwspinlock_pdata *pdata = pdev->dev.platform_data;
84+ struct device_node *node = pdev->dev.of_node;
8485 struct hwspinlock_device *bank;
8586 struct hwspinlock *hwlock;
8687 struct resource *res;
8788 void __iomem *io_base;
8889 int num_locks, i, ret;
90+ /* Only a single hwspinlock block device is supported */
91+ int base_id = 0;
8992
90− if (!pdata)
93+ if (!node)
9194 return -ENODEV;
9295
9396 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -141,7 +144,7 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) · 47 unmodified lines
141144 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
142145
143146 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
144− pdata->base_id, num_locks);
147+ base_id, num_locks);
145148 if (ret)
146149 goto reg_fail;
147150
@@ -174,11 +177,18 @@ static int omap_hwspinlock_remove(struct platform_device *pdev) · 26 unmodified lines
174177 return 0;
175178 }
176179
180+static const struct of_device_id omap_hwspinlock_of_match[] = {
181+ { .compatible = "ti,omap4-hwspinlock", },
182+ { /* end */ },
183+};
184+MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match);
185+
177186 static struct platform_driver omap_hwspinlock_driver = {
178187 .probe = omap_hwspinlock_probe,
179188 .remove = omap_hwspinlock_remove,
180189 .driver = {
181190 .name = "omap_hwspinlock",
191+ .of_match_table = of_match_ptr(omap_hwspinlock_of_match),
182192 },
183193 };
184194
drivers/hwspinlock/qcom_hwspinlock.c+181−0
@@ -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+
31+static 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+
48+static 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+
70+static const struct hwspinlock_ops qcom_hwspinlock_ops = {
71+ .trylock = qcom_hwspinlock_trylock,
72+ .unlock = qcom_hwspinlock_unlock,
73+};
74+
75+static const struct of_device_id qcom_hwspinlock_of_match[] = {
76+ { .compatible = "qcom,sfpb-mutex" },
77+ { .compatible = "qcom,tcsr-mutex" },
78+ { }
79+};
80+MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match);
81+
82+static 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+
142+static 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+
158+static 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+
167+static 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 */
172+postcore_initcall(qcom_hwspinlock_init);
173+
174+static void __exit qcom_hwspinlock_exit(void)
175+{
176+ platform_driver_unregister(&qcom_hwspinlock_driver);
177+}
178+module_exit(qcom_hwspinlock_exit);
179+
180+MODULE_LICENSE("GPL v2");
181+MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs");
drivers/hwspinlock/sirf_hwspinlock.c+136−0
@@ -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+
23+struct 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+
35+static 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+
43+static 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+
51+static const struct hwspinlock_ops sirf_hwspinlock_ops = {
52+ .trylock = sirf_hwspinlock_trylock,
53+ .unlock = sirf_hwspinlock_unlock,
54+};
55+
56+static 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+
92+reg_failed:
93+ pm_runtime_disable(&pdev->dev);
94+ iounmap(hwspin->io_base);
95+
96+ return ret;
97+}
98+
99+static 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+
117+static const struct of_device_id sirf_hwpinlock_ids[] = {
118+ { .compatible = "sirf,hwspinlock", },
119+ {},
120+};
121+MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids);
122+
123+static 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+
132+module_platform_driver(sirf_hwspinlock_driver);
133+
134+MODULE_LICENSE("GPL v2");
135+MODULE_DESCRIPTION("SIRF Hardware spinlock driver");
136+MODULE_AUTHOR("Wei Chen <wei.chen@csr.com>");
include/linux/hwspinlock.h+7−0
@@ -26,6 +26,7 @@ · 25 unmodified lines
2626 #define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
2727
2828 struct device;
29+struct device_node;
2930 struct hwspinlock;
3031 struct hwspinlock_device;
3132 struct hwspinlock_ops;
@@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank); · 34 unmodified lines
6667 struct hwspinlock *hwspin_lock_request(void);
6768 struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
6869 int hwspin_lock_free(struct hwspinlock *hwlock);
70+int of_hwspin_lock_get_id(struct device_node *np, int index);
6971 int hwspin_lock_get_id(struct hwspinlock *hwlock);
7072 int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
7173 unsigned long *);
@@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) · 48 unmodified lines
120122 {
121123 }
122124
125+static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
126+{
127+ return 0;
128+}
129+
123130 static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
124131 {
125132 return 0;