summaryrefslogtreecommitdiffstats
path: root/drivers/reset/reset-mpfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/reset/reset-mpfs.c')
-rw-r--r--drivers/reset/reset-mpfs.c95
1 files changed, 86 insertions, 9 deletions
diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c
index 7f3fb2d472f4..710f9c1676f9 100644
--- a/drivers/reset/reset-mpfs.c
+++ b/drivers/reset/reset-mpfs.c
@@ -8,9 +8,11 @@
*/
#include <linux/auxiliary_bus.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/reset-controller.h>
#include <dt-bindings/clock/microchip,mpfs-clock.h>
#include <soc/microchip/mpfs.h>
@@ -28,20 +30,30 @@
/* block concurrent access to the soft reset register */
static DEFINE_SPINLOCK(mpfs_reset_lock);
+struct mpfs_reset {
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+};
+
+static inline struct mpfs_reset *to_mpfs_reset(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct mpfs_reset, rcdev);
+}
+
/*
* Peripheral clock resets
*/
-
static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
+ struct mpfs_reset *rst = to_mpfs_reset(rcdev);
unsigned long flags;
u32 reg;
spin_lock_irqsave(&mpfs_reset_lock, flags);
- reg = mpfs_reset_read(rcdev->dev);
+ reg = readl(rst->base);
reg |= BIT(id);
- mpfs_reset_write(rcdev->dev, reg);
+ writel(reg, rst->base);
spin_unlock_irqrestore(&mpfs_reset_lock, flags);
@@ -50,14 +62,15 @@ static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
+ struct mpfs_reset *rst = to_mpfs_reset(rcdev);
unsigned long flags;
u32 reg;
spin_lock_irqsave(&mpfs_reset_lock, flags);
- reg = mpfs_reset_read(rcdev->dev);
+ reg = readl(rst->base);
reg &= ~BIT(id);
- mpfs_reset_write(rcdev->dev, reg);
+ writel(reg, rst->base);
spin_unlock_irqrestore(&mpfs_reset_lock, flags);
@@ -66,7 +79,8 @@ static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
{
- u32 reg = mpfs_reset_read(rcdev->dev);
+ struct mpfs_reset *rst = to_mpfs_reset(rcdev);
+ u32 reg = readl(rst->base);
/*
* It is safe to return here as MPFS_NUM_RESETS makes sure the sign bit
@@ -121,11 +135,15 @@ static int mpfs_reset_probe(struct auxiliary_device *adev,
{
struct device *dev = &adev->dev;
struct reset_controller_dev *rcdev;
+ struct mpfs_reset *rst;
- rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
- if (!rcdev)
+ rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
+ if (!rst)
return -ENOMEM;
+ rst->base = (void __iomem *)adev->dev.platform_data;
+
+ rcdev = &rst->rcdev;
rcdev->dev = dev;
rcdev->dev->parent = dev->parent;
rcdev->ops = &mpfs_reset_ops;
@@ -137,9 +155,68 @@ static int mpfs_reset_probe(struct auxiliary_device *adev,
return devm_reset_controller_register(dev, rcdev);
}
+static void mpfs_reset_unregister_adev(void *_adev)
+{
+ struct auxiliary_device *adev = _adev;
+
+ auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
+}
+
+static void mpfs_reset_adev_release(struct device *dev)
+{
+ struct auxiliary_device *adev = to_auxiliary_dev(dev);
+
+ kfree(adev);
+}
+
+static struct auxiliary_device *mpfs_reset_adev_alloc(struct device *clk_dev)
+{
+ struct auxiliary_device *adev;
+ int ret;
+
+ adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+ if (!adev)
+ return ERR_PTR(-ENOMEM);
+
+ adev->name = "reset-mpfs";
+ adev->dev.parent = clk_dev;
+ adev->dev.release = mpfs_reset_adev_release;
+ adev->id = 666u;
+
+ ret = auxiliary_device_init(adev);
+ if (ret) {
+ kfree(adev);
+ return ERR_PTR(ret);
+ }
+
+ return adev;
+}
+
+int mpfs_reset_controller_register(struct device *clk_dev, void __iomem *base)
+{
+ struct auxiliary_device *adev;
+ int ret;
+
+ adev = mpfs_reset_adev_alloc(clk_dev);
+ if (IS_ERR(adev))
+ return PTR_ERR(adev);
+
+ ret = auxiliary_device_add(adev);
+ if (ret) {
+ auxiliary_device_uninit(adev);
+ return ret;
+ }
+
+ adev->dev.platform_data = (__force void *)base;
+
+ return devm_add_action_or_reset(clk_dev, mpfs_reset_unregister_adev, adev);
+}
+EXPORT_SYMBOL_NS_GPL(mpfs_reset_controller_register, MCHP_CLK_MPFS);
+
static const struct auxiliary_device_id mpfs_reset_ids[] = {
{
- .name = "clk_mpfs.reset-mpfs",
+ .name = "reset_mpfs.reset-mpfs",
},
{ }
};