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/slab.h> 13#include <linux/spinlock.h> 14#include <linux/hwspinlock.h> 15#include <linux/platform_device.h> 16#include <linux/of.h> 17#include <linux/of_address.h> 18 19#include "hwspinlock_internal.h" 20 21struct sirf_hwspinlock { 22 void __iomem *io_base; 23 struct hwspinlock_device bank; 24}; 25 26/* Number of Hardware Spinlocks*/ 27#define HW_SPINLOCK_NUMBER 30 28 29/* Hardware spinlock register offsets */ 30#define HW_SPINLOCK_BASE 0x404 31#define HW_SPINLOCK_OFFSET(x) (HW_SPINLOCK_BASE + 0x4 * (x)) 32 33static int sirf_hwspinlock_trylock(struct hwspinlock *lock) 34{ 35 void __iomem *lock_addr = lock->priv; 36 37 /* attempt to acquire the lock by reading value == 1 from it */ 38 return !!readl(lock_addr); 39} 40 41static void sirf_hwspinlock_unlock(struct hwspinlock *lock) 42{ 43 void __iomem *lock_addr = lock->priv; 44 45 /* release the lock by writing 0 to it */ 46 writel(0, lock_addr); 47} 48 49static const struct hwspinlock_ops sirf_hwspinlock_ops = { 50 .trylock = sirf_hwspinlock_trylock, 51 .unlock = sirf_hwspinlock_unlock, 52}; 53 54static int sirf_hwspinlock_probe(struct platform_device *pdev) 55{ 56 struct sirf_hwspinlock *hwspin; 57 struct hwspinlock *hwlock; 58 int idx; 59 60 if (!pdev->dev.of_node) 61 return -ENODEV; 62 63 hwspin = devm_kzalloc(&pdev->dev, 64 struct_size(hwspin, bank.lock, 65 HW_SPINLOCK_NUMBER), 66 GFP_KERNEL); 67 if (!hwspin) 68 return -ENOMEM; 69 70 /* retrieve io base */ 71 hwspin->io_base = devm_platform_ioremap_resource(pdev, 0); 72 if (IS_ERR(hwspin->io_base)) 73 return PTR_ERR(hwspin->io_base); 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 return devm_hwspin_lock_register(&pdev->dev, &hwspin->bank, 83 &sirf_hwspinlock_ops, 0, 84 HW_SPINLOCK_NUMBER); 85} 86 87static const struct of_device_id sirf_hwpinlock_ids[] = { 88 { .compatible = "sirf,hwspinlock", }, 89 {}, 90}; 91MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids); 92 93static struct platform_driver sirf_hwspinlock_driver = { 94 .probe = sirf_hwspinlock_probe, 95 .driver = { 96 .name = "atlas7_hwspinlock", 97 .of_match_table = of_match_ptr(sirf_hwpinlock_ids), 98 }, 99}; 100 101module_platform_driver(sirf_hwspinlock_driver); 102 103MODULE_LICENSE("GPL v2"); 104MODULE_DESCRIPTION("SIRF Hardware spinlock driver"); 105MODULE_AUTHOR("Wei Chen <wei.chen@csr.com>"); 106