1 // SPDX-License-Identifier: GPL-2.0-only
3 * PolarFire SoC (MPFS) Peripheral Clock Reset Controller
5 * Author: Conor Dooley <conor.dooley@microchip.com>
6 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
9 #include <linux/auxiliary_bus.h>
10 #include <linux/delay.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/reset-controller.h>
17 #include <dt-bindings/clock/microchip,mpfs-clock.h>
18 #include <soc/microchip/mpfs.h>
21 * The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
22 * defines in the dt to make things easier to configure - so this is accounting
23 * for the offset of 3 there.
25 #define MPFS_PERIPH_OFFSET CLK_ENVM
26 #define MPFS_NUM_RESETS 30u
27 #define MPFS_SLEEP_MIN_US 100
28 #define MPFS_SLEEP_MAX_US 200
30 /* block concurrent access to the soft reset register */
31 static DEFINE_SPINLOCK(mpfs_reset_lock
);
35 struct reset_controller_dev rcdev
;
38 static inline struct mpfs_reset
*to_mpfs_reset(struct reset_controller_dev
*rcdev
)
40 return container_of(rcdev
, struct mpfs_reset
, rcdev
);
44 * Peripheral clock resets
46 static int mpfs_assert(struct reset_controller_dev
*rcdev
, unsigned long id
)
48 struct mpfs_reset
*rst
= to_mpfs_reset(rcdev
);
52 spin_lock_irqsave(&mpfs_reset_lock
, flags
);
54 reg
= readl(rst
->base
);
56 writel(reg
, rst
->base
);
58 spin_unlock_irqrestore(&mpfs_reset_lock
, flags
);
63 static int mpfs_deassert(struct reset_controller_dev
*rcdev
, unsigned long id
)
65 struct mpfs_reset
*rst
= to_mpfs_reset(rcdev
);
69 spin_lock_irqsave(&mpfs_reset_lock
, flags
);
71 reg
= readl(rst
->base
);
73 writel(reg
, rst
->base
);
75 spin_unlock_irqrestore(&mpfs_reset_lock
, flags
);
80 static int mpfs_status(struct reset_controller_dev
*rcdev
, unsigned long id
)
82 struct mpfs_reset
*rst
= to_mpfs_reset(rcdev
);
83 u32 reg
= readl(rst
->base
);
86 * It is safe to return here as MPFS_NUM_RESETS makes sure the sign bit
89 return (reg
& BIT(id
));
92 static int mpfs_reset(struct reset_controller_dev
*rcdev
, unsigned long id
)
94 mpfs_assert(rcdev
, id
);
96 usleep_range(MPFS_SLEEP_MIN_US
, MPFS_SLEEP_MAX_US
);
98 mpfs_deassert(rcdev
, id
);
103 static const struct reset_control_ops mpfs_reset_ops
= {
105 .assert = mpfs_assert
,
106 .deassert
= mpfs_deassert
,
107 .status
= mpfs_status
,
110 static int mpfs_reset_xlate(struct reset_controller_dev
*rcdev
,
111 const struct of_phandle_args
*reset_spec
)
113 unsigned int index
= reset_spec
->args
[0];
116 * CLK_RESERVED does not map to a clock, but it does map to a reset,
117 * so it has to be accounted for here. It is the reset for the fabric,
118 * so if this reset gets called - do not reset it.
120 if (index
== CLK_RESERVED
) {
121 dev_err(rcdev
->dev
, "Resetting the fabric is not supported\n");
125 if (index
< MPFS_PERIPH_OFFSET
|| index
>= (MPFS_PERIPH_OFFSET
+ rcdev
->nr_resets
)) {
126 dev_err(rcdev
->dev
, "Invalid reset index %u\n", index
);
130 return index
- MPFS_PERIPH_OFFSET
;
133 static int mpfs_reset_probe(struct auxiliary_device
*adev
,
134 const struct auxiliary_device_id
*id
)
136 struct device
*dev
= &adev
->dev
;
137 struct reset_controller_dev
*rcdev
;
138 struct mpfs_reset
*rst
;
140 rst
= devm_kzalloc(dev
, sizeof(*rst
), GFP_KERNEL
);
144 rst
->base
= (void __iomem
*)adev
->dev
.platform_data
;
148 rcdev
->dev
->parent
= dev
->parent
;
149 rcdev
->ops
= &mpfs_reset_ops
;
150 rcdev
->of_node
= dev
->parent
->of_node
;
151 rcdev
->of_reset_n_cells
= 1;
152 rcdev
->of_xlate
= mpfs_reset_xlate
;
153 rcdev
->nr_resets
= MPFS_NUM_RESETS
;
155 return devm_reset_controller_register(dev
, rcdev
);
158 static void mpfs_reset_unregister_adev(void *_adev
)
160 struct auxiliary_device
*adev
= _adev
;
162 auxiliary_device_delete(adev
);
163 auxiliary_device_uninit(adev
);
166 static void mpfs_reset_adev_release(struct device
*dev
)
168 struct auxiliary_device
*adev
= to_auxiliary_dev(dev
);
173 static struct auxiliary_device
*mpfs_reset_adev_alloc(struct device
*clk_dev
)
175 struct auxiliary_device
*adev
;
178 adev
= kzalloc(sizeof(*adev
), GFP_KERNEL
);
180 return ERR_PTR(-ENOMEM
);
182 adev
->name
= "reset-mpfs";
183 adev
->dev
.parent
= clk_dev
;
184 adev
->dev
.release
= mpfs_reset_adev_release
;
187 ret
= auxiliary_device_init(adev
);
196 int mpfs_reset_controller_register(struct device
*clk_dev
, void __iomem
*base
)
198 struct auxiliary_device
*adev
;
201 adev
= mpfs_reset_adev_alloc(clk_dev
);
203 return PTR_ERR(adev
);
205 ret
= auxiliary_device_add(adev
);
207 auxiliary_device_uninit(adev
);
211 adev
->dev
.platform_data
= (__force
void *)base
;
213 return devm_add_action_or_reset(clk_dev
, mpfs_reset_unregister_adev
, adev
);
215 EXPORT_SYMBOL_NS_GPL(mpfs_reset_controller_register
, "MCHP_CLK_MPFS");
217 static const struct auxiliary_device_id mpfs_reset_ids
[] = {
219 .name
= "reset_mpfs.reset-mpfs",
223 MODULE_DEVICE_TABLE(auxiliary
, mpfs_reset_ids
);
225 static struct auxiliary_driver mpfs_reset_driver
= {
226 .probe
= mpfs_reset_probe
,
227 .id_table
= mpfs_reset_ids
,
230 module_auxiliary_driver(mpfs_reset_driver
);
232 MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
233 MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
234 MODULE_IMPORT_NS("MCHP_CLK_MPFS");