linux/drivers/hwspinlock/sirf_hwspinlock.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * SIRF hardware spinlock driver
   4 *
   5 * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company.
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/device.h>
  11#include <linux/io.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>
  17#include <linux/of.h>
  18#include <linux/of_address.h>
  19
  20#include "hwspinlock_internal.h"
  21
  22struct sirf_hwspinlock {
  23        void __iomem *io_base;
  24        struct hwspinlock_device bank;
  25};
  26
  27/* Number of Hardware Spinlocks*/
  28#define HW_SPINLOCK_NUMBER      30
  29
  30/* Hardware spinlock register offsets */
  31#define HW_SPINLOCK_BASE        0x404
  32#define HW_SPINLOCK_OFFSET(x)   (HW_SPINLOCK_BASE + 0x4 * (x))
  33
  34static int sirf_hwspinlock_trylock(struct hwspinlock *lock)
  35{
  36        void __iomem *lock_addr = lock->priv;
  37
  38        /* attempt to acquire the lock by reading value == 1 from it */
  39        return !!readl(lock_addr);
  40}
  41
  42static void sirf_hwspinlock_unlock(struct hwspinlock *lock)
  43{
  44        void __iomem *lock_addr = lock->priv;
  45
  46        /* release the lock by writing 0 to it */
  47        writel(0, lock_addr);
  48}
  49
  50static const struct hwspinlock_ops sirf_hwspinlock_ops = {
  51        .trylock = sirf_hwspinlock_trylock,
  52        .unlock = sirf_hwspinlock_unlock,
  53};
  54
  55static int sirf_hwspinlock_probe(struct platform_device *pdev)
  56{
  57        struct sirf_hwspinlock *hwspin;
  58        struct hwspinlock *hwlock;
  59        int idx, ret;
  60
  61        if (!pdev->dev.of_node)
  62                return -ENODEV;
  63
  64        hwspin = devm_kzalloc(&pdev->dev,
  65                              struct_size(hwspin, bank.lock,
  66                                          HW_SPINLOCK_NUMBER),
  67                              GFP_KERNEL);
  68        if (!hwspin)
  69                return -ENOMEM;
  70
  71        /* retrieve io base */
  72        hwspin->io_base = of_iomap(pdev->dev.of_node, 0);
  73        if (!hwspin->io_base)
  74                return -ENOMEM;
  75
  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);
  79        }
  80
  81        platform_set_drvdata(pdev, hwspin);
  82
  83        pm_runtime_enable(&pdev->dev);
  84
  85        ret = hwspin_lock_register(&hwspin->bank, &pdev->dev,
  86                                   &sirf_hwspinlock_ops, 0,
  87                                   HW_SPINLOCK_NUMBER);
  88        if (ret)
  89                goto reg_failed;
  90
  91        return 0;
  92
  93reg_failed:
  94        pm_runtime_disable(&pdev->dev);
  95        iounmap(hwspin->io_base);
  96
  97        return ret;
  98}
  99
 100static int sirf_hwspinlock_remove(struct platform_device *pdev)
 101{
 102        struct sirf_hwspinlock *hwspin = platform_get_drvdata(pdev);
 103        int ret;
 104
 105        ret = hwspin_lock_unregister(&hwspin->bank);
 106        if (ret) {
 107                dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
 108                return ret;
 109        }
 110
 111        pm_runtime_disable(&pdev->dev);
 112
 113        iounmap(hwspin->io_base);
 114
 115        return 0;
 116}
 117
 118static const struct of_device_id sirf_hwpinlock_ids[] = {
 119        { .compatible = "sirf,hwspinlock", },
 120        {},
 121};
 122MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids);
 123
 124static struct platform_driver sirf_hwspinlock_driver = {
 125        .probe = sirf_hwspinlock_probe,
 126        .remove = sirf_hwspinlock_remove,
 127        .driver = {
 128                .name = "atlas7_hwspinlock",
 129                .of_match_table = of_match_ptr(sirf_hwpinlock_ids),
 130        },
 131};
 132
 133module_platform_driver(sirf_hwspinlock_driver);
 134
 135MODULE_LICENSE("GPL v2");
 136MODULE_DESCRIPTION("SIRF Hardware spinlock driver");
 137MODULE_AUTHOR("Wei Chen <wei.chen@csr.com>");
 138