summaryrefslogtreecommitdiff
path: root/drivers/hwspinlock
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwspinlock')
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c172
-rw-r--r--drivers/hwspinlock/hwspinlock_internal.h3
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c67
-rw-r--r--drivers/hwspinlock/qcom_hwspinlock.c103
-rw-r--r--drivers/hwspinlock/sprd_hwspinlock.c3
-rw-r--r--drivers/hwspinlock/stm32_hwspinlock.c60
-rw-r--r--drivers/hwspinlock/u8500_hsem.c4
7 files changed, 199 insertions, 213 deletions
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index fd5f5c5a5244..cc8e952a6772 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -84,8 +84,9 @@ static DEFINE_MUTEX(hwspinlock_tree_lock);
* should decide between spin_trylock, spin_trylock_irq and
* spin_trylock_irqsave.
*
- * Returns 0 if we successfully locked the hwspinlock or -EBUSY if
+ * Returns: %0 if we successfully locked the hwspinlock or -EBUSY if
* the hwspinlock was already taken.
+ *
* This function will never sleep.
*/
int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
@@ -171,7 +172,7 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock);
/**
* __hwspin_lock_timeout() - lock an hwspinlock with timeout limit
* @hwlock: the hwspinlock to be locked
- * @timeout: timeout value in msecs
+ * @to: timeout value in msecs
* @mode: mode which controls whether local interrupts are disabled or not
* @flags: a pointer to where the caller's interrupt state will be saved at (if
* requested)
@@ -199,9 +200,11 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock);
* to choose the appropriate @mode of operation, exactly the same way users
* should decide between spin_lock, spin_lock_irq and spin_lock_irqsave.
*
- * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * Returns: %0 when the @hwlock was successfully taken, and an appropriate
* error code otherwise (most notably -ETIMEDOUT if the @hwlock is still
- * busy after @timeout msecs). The function will never sleep.
+ * busy after @timeout msecs).
+ *
+ * The function will never sleep.
*/
int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
int mode, unsigned long *flags)
@@ -303,14 +306,41 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
EXPORT_SYMBOL_GPL(__hwspin_unlock);
/**
+ * hwspin_lock_bust() - bust a specific hwspinlock
+ * @hwlock: a previously-acquired hwspinlock which we want to bust
+ * @id: identifier of the remote lock holder, if applicable
+ *
+ * This function will bust a hwspinlock that was previously acquired as
+ * long as the current owner of the lock matches the id given by the caller.
+ *
+ * Context: Process context.
+ *
+ * Returns: 0 on success, or -EINVAL if the hwspinlock does not exist, or
+ * the bust operation fails, and -EOPNOTSUPP if the bust operation is not
+ * defined for the hwspinlock.
+ */
+int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id)
+{
+ if (WARN_ON(!hwlock))
+ return -EINVAL;
+
+ if (!hwlock->bank->ops->bust) {
+ pr_err("bust operation not defined\n");
+ return -EOPNOTSUPP;
+ }
+
+ return hwlock->bank->ops->bust(hwlock, id);
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_bust);
+
+/**
* 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,
+ * Returns: a relative index of the lock within a specified bank on success,
* or -EINVAL on invalid specifier cell count.
*/
static inline int
@@ -332,9 +362,10 @@ of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
* 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.
+ * 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)
{
@@ -367,7 +398,7 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
continue;
}
- if (hwlock->bank->dev->of_node == args.np) {
+ if (device_match_of_node(hwlock->bank->dev, args.np)) {
ret = 0;
break;
}
@@ -399,9 +430,10 @@ EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
* 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.
+ * 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_byname(struct device_node *np, const char *name)
{
@@ -481,7 +513,7 @@ out:
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
const struct hwspinlock_ops *ops, int base_id, int num_locks)
@@ -529,7 +561,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_register);
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int hwspin_lock_unregister(struct hwspinlock_device *bank)
{
@@ -578,7 +610,7 @@ static int devm_hwspin_lock_device_match(struct device *dev, void *res,
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int devm_hwspin_lock_unregister(struct device *dev,
struct hwspinlock_device *bank)
@@ -607,7 +639,7 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_unregister);
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int devm_hwspin_lock_register(struct device *dev,
struct hwspinlock_device *bank,
@@ -635,12 +667,13 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_register);
/**
* __hwspin_lock_request() - tag an hwspinlock as used and power it up
+ * @hwlock: the target hwspinlock
*
* This is an internal function that prepares an hwspinlock instance
* before it is given to the user. The function assumes that
* hwspinlock_tree_lock is taken.
*
- * Returns 0 or positive to indicate success, and a negative value to
+ * Returns: %0 or positive to indicate success, and a negative value to
* indicate an error (with the appropriate error code)
*/
static int __hwspin_lock_request(struct hwspinlock *hwlock)
@@ -677,66 +710,6 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock)
}
/**
- * hwspin_lock_get_id() - retrieve id number of a given hwspinlock
- * @hwlock: a valid hwspinlock instance
- *
- * Returns the id number of a given @hwlock, or -EINVAL if @hwlock is invalid.
- */
-int hwspin_lock_get_id(struct hwspinlock *hwlock)
-{
- if (!hwlock) {
- pr_err("invalid hwlock\n");
- return -EINVAL;
- }
-
- return hwlock_to_id(hwlock);
-}
-EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
-
-/**
- * hwspin_lock_request() - request an hwspinlock
- *
- * This function should be called by users of the hwspinlock device,
- * in order to dynamically assign them an unused hwspinlock.
- * Usually the user of this lock will then have to communicate the lock's id
- * to the remote core before it can be used for synchronization (to get the
- * id of a given hwlock, use hwspin_lock_get_id()).
- *
- * Should be called from a process context (might sleep)
- *
- * Returns the address of the assigned hwspinlock, or NULL on error
- */
-struct hwspinlock *hwspin_lock_request(void)
-{
- struct hwspinlock *hwlock;
- int ret;
-
- mutex_lock(&hwspinlock_tree_lock);
-
- /* look for an unused lock */
- ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock,
- 0, 1, HWSPINLOCK_UNUSED);
- if (ret == 0) {
- pr_warn("a free hwspinlock is not available\n");
- hwlock = NULL;
- goto out;
- }
-
- /* sanity check that should never fail */
- WARN_ON(ret > 1);
-
- /* mark as used and power up */
- ret = __hwspin_lock_request(hwlock);
- if (ret < 0)
- hwlock = NULL;
-
-out:
- mutex_unlock(&hwspinlock_tree_lock);
- return hwlock;
-}
-EXPORT_SYMBOL_GPL(hwspin_lock_request);
-
-/**
* hwspin_lock_request_specific() - request for a specific hwspinlock
* @id: index of the specific hwspinlock that is requested
*
@@ -747,7 +720,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request);
*
* Should be called from a process context (might sleep)
*
- * Returns the address of the assigned hwspinlock, or NULL on error
+ * Returns: the address of the assigned hwspinlock, or %NULL on error
*/
struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
{
@@ -795,7 +768,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int hwspin_lock_free(struct hwspinlock *hwlock)
{
@@ -865,7 +838,7 @@ static void devm_hwspin_lock_release(struct device *dev, void *res)
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock)
{
@@ -880,40 +853,6 @@ int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock)
EXPORT_SYMBOL_GPL(devm_hwspin_lock_free);
/**
- * devm_hwspin_lock_request() - request an hwspinlock for a managed device
- * @dev: the device to request an hwspinlock
- *
- * This function should be called by users of the hwspinlock device,
- * in order to dynamically assign them an unused hwspinlock.
- * Usually the user of this lock will then have to communicate the lock's id
- * to the remote core before it can be used for synchronization (to get the
- * id of a given hwlock, use hwspin_lock_get_id()).
- *
- * Should be called from a process context (might sleep)
- *
- * Returns the address of the assigned hwspinlock, or NULL on error
- */
-struct hwspinlock *devm_hwspin_lock_request(struct device *dev)
-{
- struct hwspinlock **ptr, *hwlock;
-
- ptr = devres_alloc(devm_hwspin_lock_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- hwlock = hwspin_lock_request();
- if (hwlock) {
- *ptr = hwlock;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
-
- return hwlock;
-}
-EXPORT_SYMBOL_GPL(devm_hwspin_lock_request);
-
-/**
* devm_hwspin_lock_request_specific() - request for a specific hwspinlock for
* a managed device
* @dev: the device to request the specific hwspinlock
@@ -926,7 +865,7 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_request);
*
* Should be called from a process context (might sleep)
*
- * Returns the address of the assigned hwspinlock, or NULL on error
+ * Returns: the address of the assigned hwspinlock, or %NULL on error
*/
struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev,
unsigned int id)
@@ -949,6 +888,5 @@ struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_hwspin_lock_request_specific);
-MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Hardware spinlock interface");
MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h
index 29892767bb7a..f298fc0ee5ad 100644
--- a/drivers/hwspinlock/hwspinlock_internal.h
+++ b/drivers/hwspinlock/hwspinlock_internal.h
@@ -21,6 +21,8 @@ struct hwspinlock_device;
* @trylock: make a single attempt to take the lock. returns 0 on
* failure and true on success. may _not_ sleep.
* @unlock: release the lock. always succeed. may _not_ sleep.
+ * @bust: optional, platform-specific bust handler, called by hwspinlock
+ * core to bust a specific lock.
* @relax: optional, platform-specific relax handler, called by hwspinlock
* core while spinning on a lock, between two successive
* invocations of @trylock. may _not_ sleep.
@@ -28,6 +30,7 @@ struct hwspinlock_device;
struct hwspinlock_ops {
int (*trylock)(struct hwspinlock *lock);
void (*unlock)(struct hwspinlock *lock);
+ int (*bust)(struct hwspinlock *lock, unsigned int id);
void (*relax)(struct hwspinlock *lock);
};
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index 33eeff94fc2a..27b47b8623c0 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -74,17 +74,12 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = {
static int omap_hwspinlock_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
struct hwspinlock_device *bank;
- struct hwspinlock *hwlock;
void __iomem *io_base;
int num_locks, i, ret;
/* Only a single hwspinlock block device is supported */
int base_id = 0;
- if (!node)
- return -ENODEV;
-
io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(io_base))
return PTR_ERR(io_base);
@@ -93,12 +88,10 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
* make sure the module is enabled and clocked before reading
* the module SYSSTATUS register
*/
- pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&pdev->dev);
- goto runtime_err;
- }
+ devm_pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ return ret;
/* Determine number of locks */
i = readl(io_base + SYSSTATUS_OFFSET);
@@ -110,57 +103,24 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
*/
ret = pm_runtime_put(&pdev->dev);
if (ret < 0)
- goto runtime_err;
+ return ret;
/* one of the four lsb's must be set, and nothing else */
- if (hweight_long(i & 0xf) != 1 || i > 8) {
- ret = -EINVAL;
- goto runtime_err;
- }
+ if (hweight_long(i & 0xf) != 1 || i > 8)
+ return -EINVAL;
num_locks = i * 32; /* actual number of locks in this device */
bank = devm_kzalloc(&pdev->dev, struct_size(bank, lock, num_locks),
GFP_KERNEL);
- if (!bank) {
- ret = -ENOMEM;
- goto runtime_err;
- }
+ if (!bank)
+ return -ENOMEM;
- platform_set_drvdata(pdev, bank);
+ for (i = 0; i < num_locks; i++)
+ bank->lock[i].priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
- for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
- hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
-
- ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
+ return devm_hwspin_lock_register(&pdev->dev, bank, &omap_hwspinlock_ops,
base_id, num_locks);
- if (ret)
- goto runtime_err;
-
- dev_dbg(&pdev->dev, "Registered %d locks with HwSpinlock core\n",
- num_locks);
-
- return 0;
-
-runtime_err:
- pm_runtime_disable(&pdev->dev);
- return ret;
-}
-
-static int omap_hwspinlock_remove(struct platform_device *pdev)
-{
- struct hwspinlock_device *bank = platform_get_drvdata(pdev);
- int ret;
-
- ret = hwspin_lock_unregister(bank);
- if (ret) {
- dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
- return ret;
- }
-
- pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct of_device_id omap_hwspinlock_of_match[] = {
@@ -173,10 +133,9 @@ MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match);
static struct platform_driver omap_hwspinlock_driver = {
.probe = omap_hwspinlock_probe,
- .remove = omap_hwspinlock_remove,
.driver = {
.name = "omap_hwspinlock",
- .of_match_table = of_match_ptr(omap_hwspinlock_of_match),
+ .of_match_table = omap_hwspinlock_of_match,
},
};
diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c
index 364710966665..0390979fd765 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -19,6 +19,12 @@
#define QCOM_MUTEX_APPS_PROC_ID 1
#define QCOM_MUTEX_NUM_LOCKS 32
+struct qcom_hwspinlock_of_data {
+ u32 offset;
+ u32 stride;
+ const struct regmap_config *regmap_config;
+};
+
static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
{
struct regmap_field *field = lock->priv;
@@ -58,14 +64,85 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
pr_err("%s: failed to unlock spinlock\n", __func__);
}
+static int qcom_hwspinlock_bust(struct hwspinlock *lock, unsigned int id)
+{
+ struct regmap_field *field = lock->priv;
+ u32 owner;
+ int ret;
+
+ ret = regmap_field_read(field, &owner);
+ if (ret) {
+ dev_err(lock->bank->dev, "unable to query spinlock owner\n");
+ return ret;
+ }
+
+ if (owner != id)
+ return 0;
+
+ ret = regmap_field_write(field, 0);
+ if (ret) {
+ dev_err(lock->bank->dev, "failed to bust spinlock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct hwspinlock_ops qcom_hwspinlock_ops = {
.trylock = qcom_hwspinlock_trylock,
.unlock = qcom_hwspinlock_unlock,
+ .bust = qcom_hwspinlock_bust,
+};
+
+static const struct regmap_config sfpb_mutex_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x100,
+ .fast_io = true,
+};
+
+static const struct qcom_hwspinlock_of_data of_sfpb_mutex = {
+ .offset = 0x4,
+ .stride = 0x4,
+ .regmap_config = &sfpb_mutex_config,
+};
+
+static const struct regmap_config tcsr_msm8226_mutex_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1000,
+ .fast_io = true,
+};
+
+static const struct qcom_hwspinlock_of_data of_msm8226_tcsr_mutex = {
+ .offset = 0,
+ .stride = 0x80,
+ .regmap_config = &tcsr_msm8226_mutex_config,
+};
+
+static const struct regmap_config tcsr_mutex_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x20000,
+ .fast_io = true,
+};
+
+static const struct qcom_hwspinlock_of_data of_tcsr_mutex = {
+ .offset = 0,
+ .stride = 0x1000,
+ .regmap_config = &tcsr_mutex_config,
};
static const struct of_device_id qcom_hwspinlock_of_match[] = {
- { .compatible = "qcom,sfpb-mutex" },
- { .compatible = "qcom,tcsr-mutex" },
+ { .compatible = "qcom,sfpb-mutex", .data = &of_sfpb_mutex },
+ { .compatible = "qcom,tcsr-mutex", .data = &of_tcsr_mutex },
+ { .compatible = "qcom,apq8084-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,msm8226-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,msm8974-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
+ { .compatible = "qcom,msm8994-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match);
@@ -101,29 +178,25 @@ static struct regmap *qcom_hwspinlock_probe_syscon(struct platform_device *pdev,
return regmap;
}
-static const struct regmap_config tcsr_mutex_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = 0x40000,
- .fast_io = true,
-};
-
static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev,
u32 *offset, u32 *stride)
{
+ const struct qcom_hwspinlock_of_data *data;
struct device *dev = &pdev->dev;
void __iomem *base;
- /* All modern platform has offset 0 and stride of 4k */
- *offset = 0;
- *stride = 0x1000;
+ data = of_device_get_match_data(dev);
+ if (!data->regmap_config)
+ return ERR_PTR(-EINVAL);
+
+ *offset = data->offset;
+ *stride = data->stride;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return ERR_CAST(base);
- return devm_regmap_init_mmio(dev, base, &tcsr_mutex_config);
+ return devm_regmap_init_mmio(dev, base, data->regmap_config);
}
static int qcom_hwspinlock_probe(struct platform_device *pdev)
@@ -157,6 +230,8 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev)
bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev,
regmap, field);
+ if (IS_ERR(bank->lock[i].priv))
+ return PTR_ERR(bank->lock[i].priv);
}
return devm_hwspin_lock_register(&pdev->dev, bank, &qcom_hwspinlock_ops,
diff --git a/drivers/hwspinlock/sprd_hwspinlock.c b/drivers/hwspinlock/sprd_hwspinlock.c
index d221fc9d756d..22e2ffb91743 100644
--- a/drivers/hwspinlock/sprd_hwspinlock.c
+++ b/drivers/hwspinlock/sprd_hwspinlock.c
@@ -93,8 +93,7 @@ static int sprd_hwspinlock_probe(struct platform_device *pdev)
return -ENODEV;
sprd_hwlock = devm_kzalloc(&pdev->dev,
- sizeof(struct sprd_hwspinlock_dev) +
- SPRD_HWLOCKS_NUM * sizeof(*lock),
+ struct_size(sprd_hwlock, bank.lock, SPRD_HWLOCKS_NUM),
GFP_KERNEL);
if (!sprd_hwlock)
return -ENOMEM;
diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c
index 3ad0ce0da4d9..bb5c7e5f7a80 100644
--- a/drivers/hwspinlock/stm32_hwspinlock.c
+++ b/drivers/hwspinlock/stm32_hwspinlock.c
@@ -54,53 +54,68 @@ static const struct hwspinlock_ops stm32_hwspinlock_ops = {
.relax = stm32_hwspinlock_relax,
};
+static void stm32_hwspinlock_disable_clk(void *data)
+{
+ struct platform_device *pdev = data;
+ struct stm32_hwspinlock *hw = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_get_sync(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+
+ clk_disable_unprepare(hw->clk);
+}
+
static int stm32_hwspinlock_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct stm32_hwspinlock *hw;
void __iomem *io_base;
- size_t array_size;
int i, ret;
io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(io_base))
return PTR_ERR(io_base);
- array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
- hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL);
+ hw = devm_kzalloc(dev, struct_size(hw, bank.lock, STM32_MUTEX_NUM_LOCKS), GFP_KERNEL);
if (!hw)
return -ENOMEM;
- hw->clk = devm_clk_get(&pdev->dev, "hsem");
+ hw->clk = devm_clk_get(dev, "hsem");
if (IS_ERR(hw->clk))
return PTR_ERR(hw->clk);
- for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++)
- hw->bank.lock[i].priv = io_base + i * sizeof(u32);
+ ret = clk_prepare_enable(hw->clk);
+ if (ret) {
+ dev_err(dev, "Failed to prepare_enable clock\n");
+ return ret;
+ }
platform_set_drvdata(pdev, hw);
- pm_runtime_enable(&pdev->dev);
- ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops,
- 0, STM32_MUTEX_NUM_LOCKS);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_put(dev);
- if (ret)
- pm_runtime_disable(&pdev->dev);
+ ret = devm_add_action_or_reset(dev, stm32_hwspinlock_disable_clk, pdev);
+ if (ret) {
+ dev_err(dev, "Failed to register action\n");
+ return ret;
+ }
- return ret;
-}
+ for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++)
+ hw->bank.lock[i].priv = io_base + i * sizeof(u32);
-static int stm32_hwspinlock_remove(struct platform_device *pdev)
-{
- struct stm32_hwspinlock *hw = platform_get_drvdata(pdev);
- int ret;
+ ret = devm_hwspin_lock_register(dev, &hw->bank, &stm32_hwspinlock_ops,
+ 0, STM32_MUTEX_NUM_LOCKS);
- ret = hwspin_lock_unregister(&hw->bank);
if (ret)
- dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
-
- pm_runtime_disable(&pdev->dev);
+ dev_err(dev, "Failed to register hwspinlock\n");
- return 0;
+ return ret;
}
static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev)
@@ -135,7 +150,6 @@ MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids);
static struct platform_driver stm32_hwspinlock_driver = {
.probe = stm32_hwspinlock_probe,
- .remove = stm32_hwspinlock_remove,
.driver = {
.name = "stm32_hwspinlock",
.of_match_table = stm32_hwpinlock_ids,
diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c
index 67845c0c9701..5a2d8c3e0d80 100644
--- a/drivers/hwspinlock/u8500_hsem.c
+++ b/drivers/hwspinlock/u8500_hsem.c
@@ -120,15 +120,13 @@ static int u8500_hsem_probe(struct platform_device *pdev)
pdata->base_id, num_locks);
}
-static int u8500_hsem_remove(struct platform_device *pdev)
+static void u8500_hsem_remove(struct platform_device *pdev)
{
struct hwspinlock_device *bank = platform_get_drvdata(pdev);
void __iomem *io_base = bank->lock[0].priv - HSEM_REGISTER_OFFSET;
/* clear all interrupts */
writel(0xFFFF, io_base + HSEM_ICRALL);
-
- return 0;
}
static struct platform_driver u8500_hsem_driver = {