Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
0004  * Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
0005  */
0006 
0007 #include <linux/of.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/regmap.h>
0010 #include <linux/reset-controller.h>
0011 #include <linux/slab.h>
0012 #include <linux/spinlock.h>
0013 
0014 #include "clk-stm32-core.h"
0015 
0016 #define STM32_RESET_ID_MASK GENMASK(15, 0)
0017 
0018 struct stm32_reset_data {
0019     /* reset lock */
0020     spinlock_t          lock;
0021     struct reset_controller_dev rcdev;
0022     void __iomem            *membase;
0023     u32             clear_offset;
0024 };
0025 
0026 static inline struct stm32_reset_data *
0027 to_stm32_reset_data(struct reset_controller_dev *rcdev)
0028 {
0029     return container_of(rcdev, struct stm32_reset_data, rcdev);
0030 }
0031 
0032 static int stm32_reset_update(struct reset_controller_dev *rcdev,
0033                   unsigned long id, bool assert)
0034 {
0035     struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
0036     int reg_width = sizeof(u32);
0037     int bank = id / (reg_width * BITS_PER_BYTE);
0038     int offset = id % (reg_width * BITS_PER_BYTE);
0039 
0040     if (data->clear_offset) {
0041         void __iomem *addr;
0042 
0043         addr = data->membase + (bank * reg_width);
0044         if (!assert)
0045             addr += data->clear_offset;
0046 
0047         writel(BIT(offset), addr);
0048 
0049     } else {
0050         unsigned long flags;
0051         u32 reg;
0052 
0053         spin_lock_irqsave(&data->lock, flags);
0054 
0055         reg = readl(data->membase + (bank * reg_width));
0056 
0057         if (assert)
0058             reg |= BIT(offset);
0059         else
0060             reg &= ~BIT(offset);
0061 
0062         writel(reg, data->membase + (bank * reg_width));
0063 
0064         spin_unlock_irqrestore(&data->lock, flags);
0065     }
0066 
0067     return 0;
0068 }
0069 
0070 static int stm32_reset_assert(struct reset_controller_dev *rcdev,
0071                   unsigned long id)
0072 {
0073     return stm32_reset_update(rcdev, id, true);
0074 }
0075 
0076 static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
0077                 unsigned long id)
0078 {
0079     return stm32_reset_update(rcdev, id, false);
0080 }
0081 
0082 static int stm32_reset_status(struct reset_controller_dev *rcdev,
0083                   unsigned long id)
0084 {
0085     struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
0086     int reg_width = sizeof(u32);
0087     int bank = id / (reg_width * BITS_PER_BYTE);
0088     int offset = id % (reg_width * BITS_PER_BYTE);
0089     u32 reg;
0090 
0091     reg = readl(data->membase + (bank * reg_width));
0092 
0093     return !!(reg & BIT(offset));
0094 }
0095 
0096 static const struct reset_control_ops stm32_reset_ops = {
0097     .assert     = stm32_reset_assert,
0098     .deassert   = stm32_reset_deassert,
0099     .status     = stm32_reset_status,
0100 };
0101 
0102 int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
0103              void __iomem *base)
0104 {
0105     const struct stm32_rcc_match_data *data = match->data;
0106     struct stm32_reset_data *reset_data = NULL;
0107 
0108     data = match->data;
0109 
0110     reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
0111     if (!reset_data)
0112         return -ENOMEM;
0113 
0114     spin_lock_init(&reset_data->lock);
0115     reset_data->membase = base;
0116     reset_data->rcdev.owner = THIS_MODULE;
0117     reset_data->rcdev.ops = &stm32_reset_ops;
0118     reset_data->rcdev.of_node = dev_of_node(dev);
0119     reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK;
0120     reset_data->clear_offset = data->clear_offset;
0121 
0122     return reset_controller_register(&reset_data->rcdev);
0123 }