root/drivers/hwspinlock/stm32_hwspinlock.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. stm32_hwspinlock_trylock
  2. stm32_hwspinlock_unlock
  3. stm32_hwspinlock_relax
  4. stm32_hwspinlock_probe
  5. stm32_hwspinlock_remove
  6. stm32_hwspinlock_runtime_suspend
  7. stm32_hwspinlock_runtime_resume
  8. stm32_hwspinlock_init
  9. stm32_hwspinlock_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) STMicroelectronics SA 2018
   4  * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
   5  */
   6 
   7 #include <linux/clk.h>
   8 #include <linux/delay.h>
   9 #include <linux/hwspinlock.h>
  10 #include <linux/io.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/of.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/pm_runtime.h>
  16 
  17 #include "hwspinlock_internal.h"
  18 
  19 #define STM32_MUTEX_COREID      BIT(8)
  20 #define STM32_MUTEX_LOCK_BIT    BIT(31)
  21 #define STM32_MUTEX_NUM_LOCKS   32
  22 
  23 struct stm32_hwspinlock {
  24         struct clk *clk;
  25         struct hwspinlock_device bank;
  26 };
  27 
  28 static int stm32_hwspinlock_trylock(struct hwspinlock *lock)
  29 {
  30         void __iomem *lock_addr = lock->priv;
  31         u32 status;
  32 
  33         writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, lock_addr);
  34         status = readl(lock_addr);
  35 
  36         return status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID);
  37 }
  38 
  39 static void stm32_hwspinlock_unlock(struct hwspinlock *lock)
  40 {
  41         void __iomem *lock_addr = lock->priv;
  42 
  43         writel(STM32_MUTEX_COREID, lock_addr);
  44 }
  45 
  46 static void stm32_hwspinlock_relax(struct hwspinlock *lock)
  47 {
  48         ndelay(50);
  49 }
  50 
  51 static const struct hwspinlock_ops stm32_hwspinlock_ops = {
  52         .trylock        = stm32_hwspinlock_trylock,
  53         .unlock         = stm32_hwspinlock_unlock,
  54         .relax          = stm32_hwspinlock_relax,
  55 };
  56 
  57 static int stm32_hwspinlock_probe(struct platform_device *pdev)
  58 {
  59         struct stm32_hwspinlock *hw;
  60         void __iomem *io_base;
  61         struct resource *res;
  62         size_t array_size;
  63         int i, ret;
  64 
  65         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  66         io_base = devm_ioremap_resource(&pdev->dev, res);
  67         if (IS_ERR(io_base))
  68                 return PTR_ERR(io_base);
  69 
  70         array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
  71         hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL);
  72         if (!hw)
  73                 return -ENOMEM;
  74 
  75         hw->clk = devm_clk_get(&pdev->dev, "hsem");
  76         if (IS_ERR(hw->clk))
  77                 return PTR_ERR(hw->clk);
  78 
  79         for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++)
  80                 hw->bank.lock[i].priv = io_base + i * sizeof(u32);
  81 
  82         platform_set_drvdata(pdev, hw);
  83         pm_runtime_enable(&pdev->dev);
  84 
  85         ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops,
  86                                    0, STM32_MUTEX_NUM_LOCKS);
  87 
  88         if (ret)
  89                 pm_runtime_disable(&pdev->dev);
  90 
  91         return ret;
  92 }
  93 
  94 static int stm32_hwspinlock_remove(struct platform_device *pdev)
  95 {
  96         struct stm32_hwspinlock *hw = platform_get_drvdata(pdev);
  97         int ret;
  98 
  99         ret = hwspin_lock_unregister(&hw->bank);
 100         if (ret)
 101                 dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
 102 
 103         pm_runtime_disable(&pdev->dev);
 104 
 105         return 0;
 106 }
 107 
 108 static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev)
 109 {
 110         struct stm32_hwspinlock *hw = dev_get_drvdata(dev);
 111 
 112         clk_disable_unprepare(hw->clk);
 113 
 114         return 0;
 115 }
 116 
 117 static int __maybe_unused stm32_hwspinlock_runtime_resume(struct device *dev)
 118 {
 119         struct stm32_hwspinlock *hw = dev_get_drvdata(dev);
 120 
 121         clk_prepare_enable(hw->clk);
 122 
 123         return 0;
 124 }
 125 
 126 static const struct dev_pm_ops stm32_hwspinlock_pm_ops = {
 127         SET_RUNTIME_PM_OPS(stm32_hwspinlock_runtime_suspend,
 128                            stm32_hwspinlock_runtime_resume,
 129                            NULL)
 130 };
 131 
 132 static const struct of_device_id stm32_hwpinlock_ids[] = {
 133         { .compatible = "st,stm32-hwspinlock", },
 134         {},
 135 };
 136 MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids);
 137 
 138 static struct platform_driver stm32_hwspinlock_driver = {
 139         .probe          = stm32_hwspinlock_probe,
 140         .remove         = stm32_hwspinlock_remove,
 141         .driver         = {
 142                 .name   = "stm32_hwspinlock",
 143                 .of_match_table = stm32_hwpinlock_ids,
 144                 .pm     = &stm32_hwspinlock_pm_ops,
 145         },
 146 };
 147 
 148 static int __init stm32_hwspinlock_init(void)
 149 {
 150         return platform_driver_register(&stm32_hwspinlock_driver);
 151 }
 152 /* board init code might need to reserve hwspinlocks for predefined purposes */
 153 postcore_initcall(stm32_hwspinlock_init);
 154 
 155 static void __exit stm32_hwspinlock_exit(void)
 156 {
 157         platform_driver_unregister(&stm32_hwspinlock_driver);
 158 }
 159 module_exit(stm32_hwspinlock_exit);
 160 
 161 MODULE_LICENSE("GPL v2");
 162 MODULE_DESCRIPTION("Hardware spinlock driver for STM32 SoCs");
 163 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");

/* [<][>][^][v][top][bottom][index][help] */