linux/drivers/hwspinlock/sirf_hwspinlock.c
<<
>>
Prefs
   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>");
 137