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

Merge tag 'hwspinlock-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock

Pull hwspinlock updates from Ohad Ben-Cohen:

- hwspinlock core DT support from Suman Anna

- OMAP hwspinlock DT support from Suman Anna

- QCOM hwspinlock DT support from Bjorn Andersson

- a new CSR atlas7 hwspinlock driver from Wei Chen

- CSR atlas7 hwspinlock DT binding document from Wei Chen

- a tiny QCOM hwspinlock driver fix from Bjorn Andersson

* tag 'hwspinlock-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ohad/hwspinlock:
hwspinlock: qcom: Correct msb in regmap_field
DT: hwspinlock: add the CSR atlas7 hwspinlock bindings document
hwspinlock: add a CSR atlas7 driver
hwspinlock: qcom: Add support for Qualcomm HW Mutex block
DT: hwspinlock: Add binding documentation for Qualcomm hwmutex
hwspinlock/omap: add support for dt nodes
Documentation: dt: add the omap hwspinlock bindings document
hwspinlock/core: add device tree support
Documentation: dt: add common bindings for hwspinlock

+605 -68
+59
Documentation/devicetree/bindings/hwlock/hwlock.txt
··· 1 + Generic hwlock bindings 2 + ======================= 3 + 4 + Generic bindings that are common to all the hwlock platform specific driver 5 + implementations. 6 + 7 + Please also look through the individual platform specific hwlock binding 8 + documentations for identifying any additional properties specific to that 9 + platform. 10 + 11 + hwlock providers: 12 + ================= 13 + 14 + Required properties: 15 + - #hwlock-cells: Specifies the number of cells needed to represent a 16 + specific lock. 17 + 18 + hwlock users: 19 + ============= 20 + 21 + Consumers that require specific hwlock(s) should specify them using the 22 + property "hwlocks", and an optional "hwlock-names" property. 23 + 24 + Required properties: 25 + - hwlocks: List of phandle to a hwlock provider node and an 26 + associated hwlock args specifier as indicated by 27 + #hwlock-cells. The list can have just a single hwlock 28 + or multiple hwlocks, with each hwlock represented by 29 + a phandle and a corresponding args specifier. 30 + 31 + Optional properties: 32 + - hwlock-names: List of hwlock name strings defined in the same order 33 + as the hwlocks, with one name per hwlock. Consumers can 34 + use the hwlock-names to match and get a specific hwlock. 35 + 36 + 37 + 1. Example of a node using a single specific hwlock: 38 + 39 + The following example has a node requesting a hwlock in the bank defined by 40 + the node hwlock1. hwlock1 is a hwlock provider with an argument specifier 41 + of length 1. 42 + 43 + node { 44 + ... 45 + hwlocks = <&hwlock1 2>; 46 + ... 47 + }; 48 + 49 + 2. Example of a node using multiple specific hwlocks: 50 + 51 + The following example has a node requesting two hwlocks, a hwlock within 52 + the hwlock device node 'hwlock1' with #hwlock-cells value of 1, and another 53 + hwlock within the hwlock device node 'hwlock2' with #hwlock-cells value of 2. 54 + 55 + node { 56 + ... 57 + hwlocks = <&hwlock1 2>, <&hwlock2 0 3>; 58 + ... 59 + };
+26
Documentation/devicetree/bindings/hwlock/omap-hwspinlock.txt
··· 1 + OMAP4+ HwSpinlock Driver 2 + ======================== 3 + 4 + Required properties: 5 + - compatible: Should be "ti,omap4-hwspinlock" for 6 + OMAP44xx, OMAP54xx, AM33xx, AM43xx, DRA7xx SoCs 7 + - reg: Contains the hwspinlock module register address space 8 + (base address and length) 9 + - ti,hwmods: Name of the hwmod associated with the hwspinlock device 10 + - #hwlock-cells: Should be 1. The OMAP hwspinlock users will use a 11 + 0-indexed relative hwlock number as the argument 12 + specifier value for requesting a specific hwspinlock 13 + within a hwspinlock bank. 14 + 15 + Please look at the generic hwlock binding for usage information for consumers, 16 + "Documentation/devicetree/bindings/hwlock/hwlock.txt" 17 + 18 + Example: 19 + 20 + /* OMAP4 */ 21 + hwspinlock: spinlock@4a0f6000 { 22 + compatible = "ti,omap4-hwspinlock"; 23 + reg = <0x4a0f6000 0x1000>; 24 + ti,hwmods = "spinlock"; 25 + #hwlock-cells = <1>; 26 + };
+39
Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.txt
··· 1 + Qualcomm Hardware Mutex Block: 2 + 3 + The hardware block provides mutexes utilized between different processors on 4 + the SoC as part of the communication protocol used by these processors. 5 + 6 + - compatible: 7 + Usage: required 8 + Value type: <string> 9 + Definition: must be one of: 10 + "qcom,sfpb-mutex", 11 + "qcom,tcsr-mutex" 12 + 13 + - syscon: 14 + Usage: required 15 + Value type: <prop-encoded-array> 16 + Definition: one cell containing: 17 + syscon phandle 18 + offset of the hwmutex block within the syscon 19 + stride of the hwmutex registers 20 + 21 + - #hwlock-cells: 22 + Usage: required 23 + Value type: <u32> 24 + Definition: must be 1, the specified cell represent the lock id 25 + (hwlock standard property, see hwlock.txt) 26 + 27 + Example: 28 + 29 + tcsr_mutex_block: syscon@fd484000 { 30 + compatible = "syscon"; 31 + reg = <0xfd484000 0x2000>; 32 + }; 33 + 34 + hwlock@fd484000 { 35 + compatible = "qcom,tcsr-mutex"; 36 + syscon = <&tcsr_mutex_block 0 0x80>; 37 + 38 + #hwlock-cells = <1>; 39 + };
+28
Documentation/devicetree/bindings/hwlock/sirf,hwspinlock.txt
··· 1 + SIRF Hardware spinlock device Binding 2 + ----------------------------------------------- 3 + 4 + Required properties : 5 + - compatible : shall contain only one of the following: 6 + "sirf,hwspinlock" 7 + 8 + - reg : the register address of hwspinlock 9 + 10 + - #hwlock-cells : hwlock users only use the hwlock id to represent a specific 11 + hwlock, so the number of cells should be <1> here. 12 + 13 + Please look at the generic hwlock binding for usage information for consumers, 14 + "Documentation/devicetree/bindings/hwlock/hwlock.txt" 15 + 16 + Example of hwlock provider: 17 + hwlock { 18 + compatible = "sirf,hwspinlock"; 19 + reg = <0x13240000 0x00010000>; 20 + #hwlock-cells = <1>; 21 + }; 22 + 23 + Example of hwlock users: 24 + node { 25 + ... 26 + hwlocks = <&hwlock 2>; 27 + ... 28 + };
+10
Documentation/hwspinlock.txt
··· 48 48 ids for predefined purposes. 49 49 Should be called from a process context (might sleep). 50 50 51 + int of_hwspin_lock_get_id(struct device_node *np, int index); 52 + - retrieve the global lock id for an OF phandle-based specific lock. 53 + This function provides a means for DT users of a hwspinlock module 54 + to get the global lock id of a specific hwspinlock, so that it can 55 + be requested using the normal hwspin_lock_request_specific() API. 56 + The function returns a lock id number on success, -EPROBE_DEFER if 57 + the hwspinlock device is not yet registered with the core, or other 58 + error values. 59 + Should be called from a process context (might sleep). 60 + 51 61 int hwspin_lock_free(struct hwspinlock *hwlock); 52 62 - free a previously-assigned hwspinlock; returns 0 on success, or an 53 63 appropriate error code on failure (e.g. -EINVAL if the hwspinlock
-1
MAINTAINERS
··· 7364 7364 L: linux-omap@vger.kernel.org 7365 7365 S: Maintained 7366 7366 F: drivers/hwspinlock/omap_hwspinlock.c 7367 - F: arch/arm/mach-omap2/hwspinlock.c 7368 7367 7369 7368 OMAP MMC SUPPORT 7370 7369 M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
-3
arch/arm/mach-omap2/Makefile
··· 274 274 275 275 smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o 276 276 obj-y += $(smsc911x-m) $(smsc911x-y) 277 - ifneq ($(CONFIG_HWSPINLOCK_OMAP),) 278 - obj-y += hwspinlock.o 279 - endif 280 277 281 278 obj-y += common-board-devices.o twl-common.o dss-common.o
-60
arch/arm/mach-omap2/hwspinlock.c
··· 1 - /* 2 - * OMAP hardware spinlock device initialization 3 - * 4 - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com 5 - * 6 - * Contact: Simon Que <sque@ti.com> 7 - * Hari Kanigeri <h-kanigeri2@ti.com> 8 - * 9 - * This program is free software; you can redistribute it and/or 10 - * modify it under the terms of the GNU General Public License 11 - * version 2 as published by the Free Software Foundation. 12 - * 13 - * This program is distributed in the hope that it will be useful, but 14 - * WITHOUT ANY WARRANTY; without even the implied warranty of 15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 - * General Public License for more details. 17 - */ 18 - 19 - #include <linux/kernel.h> 20 - #include <linux/init.h> 21 - #include <linux/err.h> 22 - #include <linux/hwspinlock.h> 23 - 24 - #include "soc.h" 25 - #include "omap_hwmod.h" 26 - #include "omap_device.h" 27 - 28 - static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = { 29 - .base_id = 0, 30 - }; 31 - 32 - static int __init hwspinlocks_init(void) 33 - { 34 - int retval = 0; 35 - struct omap_hwmod *oh; 36 - struct platform_device *pdev; 37 - const char *oh_name = "spinlock"; 38 - const char *dev_name = "omap_hwspinlock"; 39 - 40 - /* 41 - * Hwmod lookup will fail in case our platform doesn't support the 42 - * hardware spinlock module, so it is safe to run this initcall 43 - * on all omaps 44 - */ 45 - oh = omap_hwmod_lookup(oh_name); 46 - if (oh == NULL) 47 - return -EINVAL; 48 - 49 - pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata, 50 - sizeof(struct hwspinlock_pdata)); 51 - if (IS_ERR(pdev)) { 52 - pr_err("Can't build omap_device for %s:%s\n", dev_name, 53 - oh_name); 54 - retval = PTR_ERR(pdev); 55 - } 56 - 57 - return retval; 58 - } 59 - /* early board code might need to reserve specific hwspinlock instances */ 60 - omap_postcore_initcall(hwspinlocks_init);
+24
drivers/hwspinlock/Kconfig
··· 18 18 19 19 If unsure, say N. 20 20 21 + config HWSPINLOCK_QCOM 22 + tristate "Qualcomm Hardware Spinlock device" 23 + depends on ARCH_QCOM 24 + select HWSPINLOCK 25 + select MFD_SYSCON 26 + help 27 + Say y here to support the Qualcomm Hardware Mutex functionality, which 28 + provides a synchronisation mechanism for the various processors on 29 + the SoC. 30 + 31 + If unsure, say N. 32 + 33 + config HWSPINLOCK_SIRF 34 + tristate "SIRF Hardware Spinlock device" 35 + depends on ARCH_SIRF 36 + select HWSPINLOCK 37 + help 38 + Say y here to support the SIRF Hardware Spinlock device, which 39 + provides a synchronisation mechanism for the various processors 40 + on the SoC. 41 + 42 + It's safe to say n here if you're not interested in SIRF hardware 43 + spinlock or just want a bare minimum kernel. 44 + 21 45 config HSEM_U8500 22 46 tristate "STE Hardware Semaphore functionality" 23 47 depends on ARCH_U8500
+2
drivers/hwspinlock/Makefile
··· 4 4 5 5 obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o 6 6 obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o 7 + obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o 8 + obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o 7 9 obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
+79
drivers/hwspinlock/hwspinlock_core.c
··· 27 27 #include <linux/hwspinlock.h> 28 28 #include <linux/pm_runtime.h> 29 29 #include <linux/mutex.h> 30 + #include <linux/of.h> 30 31 31 32 #include "hwspinlock_internal.h" 32 33 ··· 257 256 spin_unlock(&hwlock->lock); 258 257 } 259 258 EXPORT_SYMBOL_GPL(__hwspin_unlock); 259 + 260 + /** 261 + * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id 262 + * @bank: the hwspinlock device bank 263 + * @hwlock_spec: hwlock specifier as found in the device tree 264 + * 265 + * This is a simple translation function, suitable for hwspinlock platform 266 + * drivers that only has a lock specifier length of 1. 267 + * 268 + * Returns a relative index of the lock within a specified bank on success, 269 + * or -EINVAL on invalid specifier cell count. 270 + */ 271 + static inline int 272 + of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) 273 + { 274 + if (WARN_ON(hwlock_spec->args_count != 1)) 275 + return -EINVAL; 276 + 277 + return hwlock_spec->args[0]; 278 + } 279 + 280 + /** 281 + * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock 282 + * @np: device node from which to request the specific hwlock 283 + * @index: index of the hwlock in the list of values 284 + * 285 + * This function provides a means for DT users of the hwspinlock module to 286 + * get the global lock id of a specific hwspinlock using the phandle of the 287 + * hwspinlock device, so that it can be requested using the normal 288 + * hwspin_lock_request_specific() API. 289 + * 290 + * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock 291 + * device is not yet registered, -EINVAL on invalid args specifier value or an 292 + * appropriate error as returned from the OF parsing of the DT client node. 293 + */ 294 + int of_hwspin_lock_get_id(struct device_node *np, int index) 295 + { 296 + struct of_phandle_args args; 297 + struct hwspinlock *hwlock; 298 + struct radix_tree_iter iter; 299 + void **slot; 300 + int id; 301 + int ret; 302 + 303 + ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, 304 + &args); 305 + if (ret) 306 + return ret; 307 + 308 + /* Find the hwspinlock device: we need its base_id */ 309 + ret = -EPROBE_DEFER; 310 + rcu_read_lock(); 311 + radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) { 312 + hwlock = radix_tree_deref_slot(slot); 313 + if (unlikely(!hwlock)) 314 + continue; 315 + 316 + if (hwlock->bank->dev->of_node == args.np) { 317 + ret = 0; 318 + break; 319 + } 320 + } 321 + rcu_read_unlock(); 322 + if (ret < 0) 323 + goto out; 324 + 325 + id = of_hwspin_lock_simple_xlate(&args); 326 + if (id < 0 || id >= hwlock->bank->num_locks) { 327 + ret = -EINVAL; 328 + goto out; 329 + } 330 + id += hwlock->bank->base_id; 331 + 332 + out: 333 + of_node_put(args.np); 334 + return ret ? ret : id; 335 + } 336 + EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id); 260 337 261 338 static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) 262 339 {
+14 -4
drivers/hwspinlock/omap_hwspinlock.c
··· 1 1 /* 2 2 * OMAP hardware spinlock driver 3 3 * 4 - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com 4 + * Copyright (C) 2010-2015 Texas Instruments Incorporated - http://www.ti.com 5 5 * 6 6 * Contact: Simon Que <sque@ti.com> 7 7 * Hari Kanigeri <h-kanigeri2@ti.com> ··· 27 27 #include <linux/slab.h> 28 28 #include <linux/spinlock.h> 29 29 #include <linux/hwspinlock.h> 30 + #include <linux/of.h> 30 31 #include <linux/platform_device.h> 31 32 32 33 #include "hwspinlock_internal.h" ··· 81 80 82 81 static int omap_hwspinlock_probe(struct platform_device *pdev) 83 82 { 84 - struct hwspinlock_pdata *pdata = pdev->dev.platform_data; 83 + struct device_node *node = pdev->dev.of_node; 85 84 struct hwspinlock_device *bank; 86 85 struct hwspinlock *hwlock; 87 86 struct resource *res; 88 87 void __iomem *io_base; 89 88 int num_locks, i, ret; 89 + /* Only a single hwspinlock block device is supported */ 90 + int base_id = 0; 90 91 91 - if (!pdata) 92 + if (!node) 92 93 return -ENODEV; 93 94 94 95 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ··· 144 141 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i; 145 142 146 143 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops, 147 - pdata->base_id, num_locks); 144 + base_id, num_locks); 148 145 if (ret) 149 146 goto reg_fail; 150 147 ··· 177 174 return 0; 178 175 } 179 176 177 + static const struct of_device_id omap_hwspinlock_of_match[] = { 178 + { .compatible = "ti,omap4-hwspinlock", }, 179 + { /* end */ }, 180 + }; 181 + MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match); 182 + 180 183 static struct platform_driver omap_hwspinlock_driver = { 181 184 .probe = omap_hwspinlock_probe, 182 185 .remove = omap_hwspinlock_remove, 183 186 .driver = { 184 187 .name = "omap_hwspinlock", 188 + .of_match_table = of_match_ptr(omap_hwspinlock_of_match), 185 189 }, 186 190 }; 187 191
+181
drivers/hwspinlock/qcom_hwspinlock.c
··· 1 + /* 2 + * Copyright (c) 2013, The Linux Foundation. All rights reserved. 3 + * Copyright (c) 2015, Sony Mobile Communications AB 4 + * 5 + * This software is licensed under the terms of the GNU General Public 6 + * License version 2, as published by the Free Software Foundation, and 7 + * may be copied, distributed, and modified under those terms. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <linux/hwspinlock.h> 16 + #include <linux/io.h> 17 + #include <linux/kernel.h> 18 + #include <linux/mfd/syscon.h> 19 + #include <linux/module.h> 20 + #include <linux/of.h> 21 + #include <linux/of_device.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/pm_runtime.h> 24 + #include <linux/regmap.h> 25 + 26 + #include "hwspinlock_internal.h" 27 + 28 + #define QCOM_MUTEX_APPS_PROC_ID 1 29 + #define QCOM_MUTEX_NUM_LOCKS 32 30 + 31 + static int qcom_hwspinlock_trylock(struct hwspinlock *lock) 32 + { 33 + struct regmap_field *field = lock->priv; 34 + u32 lock_owner; 35 + int ret; 36 + 37 + ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID); 38 + if (ret) 39 + return ret; 40 + 41 + ret = regmap_field_read(field, &lock_owner); 42 + if (ret) 43 + return ret; 44 + 45 + return lock_owner == QCOM_MUTEX_APPS_PROC_ID; 46 + } 47 + 48 + static void qcom_hwspinlock_unlock(struct hwspinlock *lock) 49 + { 50 + struct regmap_field *field = lock->priv; 51 + u32 lock_owner; 52 + int ret; 53 + 54 + ret = regmap_field_read(field, &lock_owner); 55 + if (ret) { 56 + pr_err("%s: unable to query spinlock owner\n", __func__); 57 + return; 58 + } 59 + 60 + if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) { 61 + pr_err("%s: spinlock not owned by us (actual owner is %d)\n", 62 + __func__, lock_owner); 63 + } 64 + 65 + ret = regmap_field_write(field, 0); 66 + if (ret) 67 + pr_err("%s: failed to unlock spinlock\n", __func__); 68 + } 69 + 70 + static const struct hwspinlock_ops qcom_hwspinlock_ops = { 71 + .trylock = qcom_hwspinlock_trylock, 72 + .unlock = qcom_hwspinlock_unlock, 73 + }; 74 + 75 + static const struct of_device_id qcom_hwspinlock_of_match[] = { 76 + { .compatible = "qcom,sfpb-mutex" }, 77 + { .compatible = "qcom,tcsr-mutex" }, 78 + { } 79 + }; 80 + MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match); 81 + 82 + static int qcom_hwspinlock_probe(struct platform_device *pdev) 83 + { 84 + struct hwspinlock_device *bank; 85 + struct device_node *syscon; 86 + struct reg_field field; 87 + struct regmap *regmap; 88 + size_t array_size; 89 + u32 stride; 90 + u32 base; 91 + int ret; 92 + int i; 93 + 94 + syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0); 95 + if (!syscon) { 96 + dev_err(&pdev->dev, "no syscon property\n"); 97 + return -ENODEV; 98 + } 99 + 100 + regmap = syscon_node_to_regmap(syscon); 101 + if (IS_ERR(regmap)) 102 + return PTR_ERR(regmap); 103 + 104 + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base); 105 + if (ret < 0) { 106 + dev_err(&pdev->dev, "no offset in syscon\n"); 107 + return -EINVAL; 108 + } 109 + 110 + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride); 111 + if (ret < 0) { 112 + dev_err(&pdev->dev, "no stride syscon\n"); 113 + return -EINVAL; 114 + } 115 + 116 + array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); 117 + bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL); 118 + if (!bank) 119 + return -ENOMEM; 120 + 121 + platform_set_drvdata(pdev, bank); 122 + 123 + for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { 124 + field.reg = base + i * stride; 125 + field.lsb = 0; 126 + field.msb = 31; 127 + 128 + bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, 129 + regmap, field); 130 + } 131 + 132 + pm_runtime_enable(&pdev->dev); 133 + 134 + ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops, 135 + 0, QCOM_MUTEX_NUM_LOCKS); 136 + if (ret) 137 + pm_runtime_disable(&pdev->dev); 138 + 139 + return ret; 140 + } 141 + 142 + static int qcom_hwspinlock_remove(struct platform_device *pdev) 143 + { 144 + struct hwspinlock_device *bank = platform_get_drvdata(pdev); 145 + int ret; 146 + 147 + ret = hwspin_lock_unregister(bank); 148 + if (ret) { 149 + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); 150 + return ret; 151 + } 152 + 153 + pm_runtime_disable(&pdev->dev); 154 + 155 + return 0; 156 + } 157 + 158 + static struct platform_driver qcom_hwspinlock_driver = { 159 + .probe = qcom_hwspinlock_probe, 160 + .remove = qcom_hwspinlock_remove, 161 + .driver = { 162 + .name = "qcom_hwspinlock", 163 + .of_match_table = qcom_hwspinlock_of_match, 164 + }, 165 + }; 166 + 167 + static int __init qcom_hwspinlock_init(void) 168 + { 169 + return platform_driver_register(&qcom_hwspinlock_driver); 170 + } 171 + /* board init code might need to reserve hwspinlocks for predefined purposes */ 172 + postcore_initcall(qcom_hwspinlock_init); 173 + 174 + static void __exit qcom_hwspinlock_exit(void) 175 + { 176 + platform_driver_unregister(&qcom_hwspinlock_driver); 177 + } 178 + module_exit(qcom_hwspinlock_exit); 179 + 180 + MODULE_LICENSE("GPL v2"); 181 + MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs");
+136
drivers/hwspinlock/sirf_hwspinlock.c
··· 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 + 23 + struct 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 + 35 + static 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 + 43 + static 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 + 51 + static const struct hwspinlock_ops sirf_hwspinlock_ops = { 52 + .trylock = sirf_hwspinlock_trylock, 53 + .unlock = sirf_hwspinlock_unlock, 54 + }; 55 + 56 + static 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 + 92 + reg_failed: 93 + pm_runtime_disable(&pdev->dev); 94 + iounmap(hwspin->io_base); 95 + 96 + return ret; 97 + } 98 + 99 + static 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 + 117 + static const struct of_device_id sirf_hwpinlock_ids[] = { 118 + { .compatible = "sirf,hwspinlock", }, 119 + {}, 120 + }; 121 + MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids); 122 + 123 + static 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 + 132 + module_platform_driver(sirf_hwspinlock_driver); 133 + 134 + MODULE_LICENSE("GPL v2"); 135 + MODULE_DESCRIPTION("SIRF Hardware spinlock driver"); 136 + MODULE_AUTHOR("Wei Chen <wei.chen@csr.com>");
+7
include/linux/hwspinlock.h
··· 26 26 #define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ 27 27 28 28 struct device; 29 + struct device_node; 29 30 struct hwspinlock; 30 31 struct hwspinlock_device; 31 32 struct hwspinlock_ops; ··· 67 66 struct hwspinlock *hwspin_lock_request(void); 68 67 struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 69 68 int hwspin_lock_free(struct hwspinlock *hwlock); 69 + int of_hwspin_lock_get_id(struct device_node *np, int index); 70 70 int hwspin_lock_get_id(struct hwspinlock *hwlock); 71 71 int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, 72 72 unsigned long *); ··· 120 118 static inline 121 119 void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) 122 120 { 121 + } 122 + 123 + static inline int of_hwspin_lock_get_id(struct device_node *np, int index) 124 + { 125 + return 0; 123 126 } 124 127 125 128 static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)