Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc1 137 lines 3.1 kB view raw
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>");