1 // SPDX-License-Identifier: GPL-2.0
3 * SIRF hardware spinlock driver
5 * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company.
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/device.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
15 #include <linux/hwspinlock.h>
16 #include <linux/platform_device.h>
18 #include <linux/of_address.h>
20 #include "hwspinlock_internal.h"
22 struct sirf_hwspinlock
{
23 void __iomem
*io_base
;
24 struct hwspinlock_device bank
;
27 /* Number of Hardware Spinlocks*/
28 #define HW_SPINLOCK_NUMBER 30
30 /* Hardware spinlock register offsets */
31 #define HW_SPINLOCK_BASE 0x404
32 #define HW_SPINLOCK_OFFSET(x) (HW_SPINLOCK_BASE + 0x4 * (x))
34 static int sirf_hwspinlock_trylock(struct hwspinlock
*lock
)
36 void __iomem
*lock_addr
= lock
->priv
;
38 /* attempt to acquire the lock by reading value == 1 from it */
39 return !!readl(lock_addr
);
42 static void sirf_hwspinlock_unlock(struct hwspinlock
*lock
)
44 void __iomem
*lock_addr
= lock
->priv
;
46 /* release the lock by writing 0 to it */
50 static const struct hwspinlock_ops sirf_hwspinlock_ops
= {
51 .trylock
= sirf_hwspinlock_trylock
,
52 .unlock
= sirf_hwspinlock_unlock
,
55 static int sirf_hwspinlock_probe(struct platform_device
*pdev
)
57 struct sirf_hwspinlock
*hwspin
;
58 struct hwspinlock
*hwlock
;
61 if (!pdev
->dev
.of_node
)
64 hwspin
= devm_kzalloc(&pdev
->dev
,
65 struct_size(hwspin
, bank
.lock
,
71 /* retrieve io base */
72 hwspin
->io_base
= of_iomap(pdev
->dev
.of_node
, 0);
76 for (idx
= 0; idx
< HW_SPINLOCK_NUMBER
; idx
++) {
77 hwlock
= &hwspin
->bank
.lock
[idx
];
78 hwlock
->priv
= hwspin
->io_base
+ HW_SPINLOCK_OFFSET(idx
);
81 platform_set_drvdata(pdev
, hwspin
);
83 pm_runtime_enable(&pdev
->dev
);
85 ret
= hwspin_lock_register(&hwspin
->bank
, &pdev
->dev
,
86 &sirf_hwspinlock_ops
, 0,
94 pm_runtime_disable(&pdev
->dev
);
95 iounmap(hwspin
->io_base
);
100 static int sirf_hwspinlock_remove(struct platform_device
*pdev
)
102 struct sirf_hwspinlock
*hwspin
= platform_get_drvdata(pdev
);
105 ret
= hwspin_lock_unregister(&hwspin
->bank
);
107 dev_err(&pdev
->dev
, "%s failed: %d\n", __func__
, ret
);
111 pm_runtime_disable(&pdev
->dev
);
113 iounmap(hwspin
->io_base
);
118 static const struct of_device_id sirf_hwpinlock_ids
[] = {
119 { .compatible
= "sirf,hwspinlock", },
122 MODULE_DEVICE_TABLE(of
, sirf_hwpinlock_ids
);
124 static struct platform_driver sirf_hwspinlock_driver
= {
125 .probe
= sirf_hwspinlock_probe
,
126 .remove
= sirf_hwspinlock_remove
,
128 .name
= "atlas7_hwspinlock",
129 .of_match_table
= of_match_ptr(sirf_hwpinlock_ids
),
133 module_platform_driver(sirf_hwspinlock_driver
);
135 MODULE_LICENSE("GPL v2");
136 MODULE_DESCRIPTION("SIRF Hardware spinlock driver");
137 MODULE_AUTHOR("Wei Chen <wei.chen@csr.com>");