xref: /linux/drivers/reset/reset-lpc18xx.c (revision c392b65ba853f653cff3d1c7de2138bd6906d536)
1*c392b65bSJoachim Eastwood /*
2*c392b65bSJoachim Eastwood  * Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU).
3*c392b65bSJoachim Eastwood  *
4*c392b65bSJoachim Eastwood  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
5*c392b65bSJoachim Eastwood  *
6*c392b65bSJoachim Eastwood  * This program is free software; you can redistribute it and/or modify
7*c392b65bSJoachim Eastwood  * it under the terms of the GNU General Public License version 2 as
8*c392b65bSJoachim Eastwood  * published by the Free Software Foundation.
9*c392b65bSJoachim Eastwood  *
10*c392b65bSJoachim Eastwood  */
11*c392b65bSJoachim Eastwood 
12*c392b65bSJoachim Eastwood #include <linux/clk.h>
13*c392b65bSJoachim Eastwood #include <linux/delay.h>
14*c392b65bSJoachim Eastwood #include <linux/err.h>
15*c392b65bSJoachim Eastwood #include <linux/io.h>
16*c392b65bSJoachim Eastwood #include <linux/module.h>
17*c392b65bSJoachim Eastwood #include <linux/of.h>
18*c392b65bSJoachim Eastwood #include <linux/platform_device.h>
19*c392b65bSJoachim Eastwood #include <linux/reboot.h>
20*c392b65bSJoachim Eastwood #include <linux/reset-controller.h>
21*c392b65bSJoachim Eastwood #include <linux/spinlock.h>
22*c392b65bSJoachim Eastwood 
23*c392b65bSJoachim Eastwood /* LPC18xx RGU registers */
24*c392b65bSJoachim Eastwood #define LPC18XX_RGU_CTRL0		0x100
25*c392b65bSJoachim Eastwood #define LPC18XX_RGU_CTRL1		0x104
26*c392b65bSJoachim Eastwood #define LPC18XX_RGU_ACTIVE_STATUS0	0x150
27*c392b65bSJoachim Eastwood #define LPC18XX_RGU_ACTIVE_STATUS1	0x154
28*c392b65bSJoachim Eastwood 
29*c392b65bSJoachim Eastwood #define LPC18XX_RGU_RESETS_PER_REG	32
30*c392b65bSJoachim Eastwood 
31*c392b65bSJoachim Eastwood /* Internal reset outputs */
32*c392b65bSJoachim Eastwood #define LPC18XX_RGU_CORE_RST	0
33*c392b65bSJoachim Eastwood #define LPC43XX_RGU_M0SUB_RST	12
34*c392b65bSJoachim Eastwood #define LPC43XX_RGU_M0APP_RST	56
35*c392b65bSJoachim Eastwood 
36*c392b65bSJoachim Eastwood struct lpc18xx_rgu_data {
37*c392b65bSJoachim Eastwood 	struct reset_controller_dev rcdev;
38*c392b65bSJoachim Eastwood 	struct clk *clk_delay;
39*c392b65bSJoachim Eastwood 	struct clk *clk_reg;
40*c392b65bSJoachim Eastwood 	void __iomem *base;
41*c392b65bSJoachim Eastwood 	spinlock_t lock;
42*c392b65bSJoachim Eastwood 	u32 delay_us;
43*c392b65bSJoachim Eastwood };
44*c392b65bSJoachim Eastwood 
45*c392b65bSJoachim Eastwood #define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev)
46*c392b65bSJoachim Eastwood 
47*c392b65bSJoachim Eastwood static void __iomem *rgu_base;
48*c392b65bSJoachim Eastwood 
49*c392b65bSJoachim Eastwood static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode,
50*c392b65bSJoachim Eastwood 			       void *cmd)
51*c392b65bSJoachim Eastwood {
52*c392b65bSJoachim Eastwood 	writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0);
53*c392b65bSJoachim Eastwood 	mdelay(2000);
54*c392b65bSJoachim Eastwood 
55*c392b65bSJoachim Eastwood 	pr_emerg("%s: unable to restart system\n", __func__);
56*c392b65bSJoachim Eastwood 
57*c392b65bSJoachim Eastwood 	return NOTIFY_DONE;
58*c392b65bSJoachim Eastwood }
59*c392b65bSJoachim Eastwood 
60*c392b65bSJoachim Eastwood static struct notifier_block lpc18xx_rgu_restart_nb = {
61*c392b65bSJoachim Eastwood 	.notifier_call = lpc18xx_rgu_restart,
62*c392b65bSJoachim Eastwood 	.priority = 192,
63*c392b65bSJoachim Eastwood };
64*c392b65bSJoachim Eastwood 
65*c392b65bSJoachim Eastwood /*
66*c392b65bSJoachim Eastwood  * The LPC18xx RGU has mostly self-deasserting resets except for the
67*c392b65bSJoachim Eastwood  * two reset lines going to the internal Cortex-M0 cores.
68*c392b65bSJoachim Eastwood  *
69*c392b65bSJoachim Eastwood  * To prevent the M0 core resets from accidentally getting deasserted
70*c392b65bSJoachim Eastwood  * status register must be check and bits in control register set to
71*c392b65bSJoachim Eastwood  * preserve the state.
72*c392b65bSJoachim Eastwood  */
73*c392b65bSJoachim Eastwood static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev,
74*c392b65bSJoachim Eastwood 				      unsigned long id, bool set)
75*c392b65bSJoachim Eastwood {
76*c392b65bSJoachim Eastwood 	struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
77*c392b65bSJoachim Eastwood 	u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0;
78*c392b65bSJoachim Eastwood 	u32 ctrl_offset = LPC18XX_RGU_CTRL0;
79*c392b65bSJoachim Eastwood 	unsigned long flags;
80*c392b65bSJoachim Eastwood 	u32 stat, rst_bit;
81*c392b65bSJoachim Eastwood 
82*c392b65bSJoachim Eastwood 	stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
83*c392b65bSJoachim Eastwood 	ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
84*c392b65bSJoachim Eastwood 	rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG);
85*c392b65bSJoachim Eastwood 
86*c392b65bSJoachim Eastwood 	spin_lock_irqsave(&rc->lock, flags);
87*c392b65bSJoachim Eastwood 	stat = ~readl(rc->base + stat_offset);
88*c392b65bSJoachim Eastwood 	if (set)
89*c392b65bSJoachim Eastwood 		writel(stat | rst_bit, rc->base + ctrl_offset);
90*c392b65bSJoachim Eastwood 	else
91*c392b65bSJoachim Eastwood 		writel(stat & ~rst_bit, rc->base + ctrl_offset);
92*c392b65bSJoachim Eastwood 	spin_unlock_irqrestore(&rc->lock, flags);
93*c392b65bSJoachim Eastwood 
94*c392b65bSJoachim Eastwood 	return 0;
95*c392b65bSJoachim Eastwood }
96*c392b65bSJoachim Eastwood 
97*c392b65bSJoachim Eastwood static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev,
98*c392b65bSJoachim Eastwood 			      unsigned long id)
99*c392b65bSJoachim Eastwood {
100*c392b65bSJoachim Eastwood 	return lpc18xx_rgu_setclear_reset(rcdev, id, true);
101*c392b65bSJoachim Eastwood }
102*c392b65bSJoachim Eastwood 
103*c392b65bSJoachim Eastwood static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev,
104*c392b65bSJoachim Eastwood 				unsigned long id)
105*c392b65bSJoachim Eastwood {
106*c392b65bSJoachim Eastwood 	return lpc18xx_rgu_setclear_reset(rcdev, id, false);
107*c392b65bSJoachim Eastwood }
108*c392b65bSJoachim Eastwood 
109*c392b65bSJoachim Eastwood /* Only M0 cores require explicit reset deassert */
110*c392b65bSJoachim Eastwood static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev,
111*c392b65bSJoachim Eastwood 			     unsigned long id)
112*c392b65bSJoachim Eastwood {
113*c392b65bSJoachim Eastwood 	struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
114*c392b65bSJoachim Eastwood 
115*c392b65bSJoachim Eastwood 	lpc18xx_rgu_assert(rcdev, id);
116*c392b65bSJoachim Eastwood 	udelay(rc->delay_us);
117*c392b65bSJoachim Eastwood 
118*c392b65bSJoachim Eastwood 	switch (id) {
119*c392b65bSJoachim Eastwood 	case LPC43XX_RGU_M0SUB_RST:
120*c392b65bSJoachim Eastwood 	case LPC43XX_RGU_M0APP_RST:
121*c392b65bSJoachim Eastwood 		lpc18xx_rgu_setclear_reset(rcdev, id, false);
122*c392b65bSJoachim Eastwood 	}
123*c392b65bSJoachim Eastwood 
124*c392b65bSJoachim Eastwood 	return 0;
125*c392b65bSJoachim Eastwood }
126*c392b65bSJoachim Eastwood 
127*c392b65bSJoachim Eastwood static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev,
128*c392b65bSJoachim Eastwood 			      unsigned long id)
129*c392b65bSJoachim Eastwood {
130*c392b65bSJoachim Eastwood 	struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
131*c392b65bSJoachim Eastwood 	u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0;
132*c392b65bSJoachim Eastwood 
133*c392b65bSJoachim Eastwood 	offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
134*c392b65bSJoachim Eastwood 	bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG);
135*c392b65bSJoachim Eastwood 
136*c392b65bSJoachim Eastwood 	return !(readl(rc->base + offset) & bit);
137*c392b65bSJoachim Eastwood }
138*c392b65bSJoachim Eastwood 
139*c392b65bSJoachim Eastwood static struct reset_control_ops lpc18xx_rgu_ops = {
140*c392b65bSJoachim Eastwood 	.reset		= lpc18xx_rgu_reset,
141*c392b65bSJoachim Eastwood 	.assert		= lpc18xx_rgu_assert,
142*c392b65bSJoachim Eastwood 	.deassert	= lpc18xx_rgu_deassert,
143*c392b65bSJoachim Eastwood 	.status		= lpc18xx_rgu_status,
144*c392b65bSJoachim Eastwood };
145*c392b65bSJoachim Eastwood 
146*c392b65bSJoachim Eastwood static int lpc18xx_rgu_probe(struct platform_device *pdev)
147*c392b65bSJoachim Eastwood {
148*c392b65bSJoachim Eastwood 	struct lpc18xx_rgu_data *rc;
149*c392b65bSJoachim Eastwood 	struct resource *res;
150*c392b65bSJoachim Eastwood 	u32 fcclk, firc;
151*c392b65bSJoachim Eastwood 	int ret;
152*c392b65bSJoachim Eastwood 
153*c392b65bSJoachim Eastwood 	rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL);
154*c392b65bSJoachim Eastwood 	if (!rc)
155*c392b65bSJoachim Eastwood 		return -ENOMEM;
156*c392b65bSJoachim Eastwood 
157*c392b65bSJoachim Eastwood 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
158*c392b65bSJoachim Eastwood 	rc->base = devm_ioremap_resource(&pdev->dev, res);
159*c392b65bSJoachim Eastwood 	if (IS_ERR(rc->base))
160*c392b65bSJoachim Eastwood 		return PTR_ERR(rc->base);
161*c392b65bSJoachim Eastwood 
162*c392b65bSJoachim Eastwood 	rc->clk_reg = devm_clk_get(&pdev->dev, "reg");
163*c392b65bSJoachim Eastwood 	if (IS_ERR(rc->clk_reg)) {
164*c392b65bSJoachim Eastwood 		dev_err(&pdev->dev, "reg clock not found\n");
165*c392b65bSJoachim Eastwood 		return PTR_ERR(rc->clk_reg);
166*c392b65bSJoachim Eastwood 	}
167*c392b65bSJoachim Eastwood 
168*c392b65bSJoachim Eastwood 	rc->clk_delay = devm_clk_get(&pdev->dev, "delay");
169*c392b65bSJoachim Eastwood 	if (IS_ERR(rc->clk_delay)) {
170*c392b65bSJoachim Eastwood 		dev_err(&pdev->dev, "delay clock not found\n");
171*c392b65bSJoachim Eastwood 		return PTR_ERR(rc->clk_delay);
172*c392b65bSJoachim Eastwood 	}
173*c392b65bSJoachim Eastwood 
174*c392b65bSJoachim Eastwood 	ret = clk_prepare_enable(rc->clk_reg);
175*c392b65bSJoachim Eastwood 	if (ret) {
176*c392b65bSJoachim Eastwood 		dev_err(&pdev->dev, "unable to enable reg clock\n");
177*c392b65bSJoachim Eastwood 		return ret;
178*c392b65bSJoachim Eastwood 	}
179*c392b65bSJoachim Eastwood 
180*c392b65bSJoachim Eastwood 	ret = clk_prepare_enable(rc->clk_delay);
181*c392b65bSJoachim Eastwood 	if (ret) {
182*c392b65bSJoachim Eastwood 		dev_err(&pdev->dev, "unable to enable delay clock\n");
183*c392b65bSJoachim Eastwood 		goto dis_clk_reg;
184*c392b65bSJoachim Eastwood 	}
185*c392b65bSJoachim Eastwood 
186*c392b65bSJoachim Eastwood 	fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC;
187*c392b65bSJoachim Eastwood 	firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC;
188*c392b65bSJoachim Eastwood 	if (fcclk == 0 || firc == 0)
189*c392b65bSJoachim Eastwood 		rc->delay_us = 2;
190*c392b65bSJoachim Eastwood 	else
191*c392b65bSJoachim Eastwood 		rc->delay_us = DIV_ROUND_UP(fcclk, firc * firc);
192*c392b65bSJoachim Eastwood 
193*c392b65bSJoachim Eastwood 	spin_lock_init(&rc->lock);
194*c392b65bSJoachim Eastwood 
195*c392b65bSJoachim Eastwood 	rc->rcdev.owner = THIS_MODULE;
196*c392b65bSJoachim Eastwood 	rc->rcdev.nr_resets = 64;
197*c392b65bSJoachim Eastwood 	rc->rcdev.ops = &lpc18xx_rgu_ops;
198*c392b65bSJoachim Eastwood 	rc->rcdev.of_node = pdev->dev.of_node;
199*c392b65bSJoachim Eastwood 
200*c392b65bSJoachim Eastwood 	platform_set_drvdata(pdev, rc);
201*c392b65bSJoachim Eastwood 
202*c392b65bSJoachim Eastwood 	ret = reset_controller_register(&rc->rcdev);
203*c392b65bSJoachim Eastwood 	if (ret) {
204*c392b65bSJoachim Eastwood 		dev_err(&pdev->dev, "unable to register device\n");
205*c392b65bSJoachim Eastwood 		goto dis_clks;
206*c392b65bSJoachim Eastwood 	}
207*c392b65bSJoachim Eastwood 
208*c392b65bSJoachim Eastwood 	rgu_base = rc->base;
209*c392b65bSJoachim Eastwood 	ret = register_restart_handler(&lpc18xx_rgu_restart_nb);
210*c392b65bSJoachim Eastwood 	if (ret)
211*c392b65bSJoachim Eastwood 		dev_warn(&pdev->dev, "failed to register restart handler\n");
212*c392b65bSJoachim Eastwood 
213*c392b65bSJoachim Eastwood 	return 0;
214*c392b65bSJoachim Eastwood 
215*c392b65bSJoachim Eastwood dis_clks:
216*c392b65bSJoachim Eastwood 	clk_disable_unprepare(rc->clk_delay);
217*c392b65bSJoachim Eastwood dis_clk_reg:
218*c392b65bSJoachim Eastwood 	clk_disable_unprepare(rc->clk_reg);
219*c392b65bSJoachim Eastwood 
220*c392b65bSJoachim Eastwood 	return ret;
221*c392b65bSJoachim Eastwood }
222*c392b65bSJoachim Eastwood 
223*c392b65bSJoachim Eastwood static int lpc18xx_rgu_remove(struct platform_device *pdev)
224*c392b65bSJoachim Eastwood {
225*c392b65bSJoachim Eastwood 	struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev);
226*c392b65bSJoachim Eastwood 	int ret;
227*c392b65bSJoachim Eastwood 
228*c392b65bSJoachim Eastwood 	ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb);
229*c392b65bSJoachim Eastwood 	if (ret)
230*c392b65bSJoachim Eastwood 		dev_warn(&pdev->dev, "failed to unregister restart handler\n");
231*c392b65bSJoachim Eastwood 
232*c392b65bSJoachim Eastwood 	reset_controller_unregister(&rc->rcdev);
233*c392b65bSJoachim Eastwood 
234*c392b65bSJoachim Eastwood 	clk_disable_unprepare(rc->clk_delay);
235*c392b65bSJoachim Eastwood 	clk_disable_unprepare(rc->clk_reg);
236*c392b65bSJoachim Eastwood 
237*c392b65bSJoachim Eastwood 	return 0;
238*c392b65bSJoachim Eastwood }
239*c392b65bSJoachim Eastwood 
240*c392b65bSJoachim Eastwood static const struct of_device_id lpc18xx_rgu_match[] = {
241*c392b65bSJoachim Eastwood 	{ .compatible = "nxp,lpc1850-rgu" },
242*c392b65bSJoachim Eastwood 	{ }
243*c392b65bSJoachim Eastwood };
244*c392b65bSJoachim Eastwood MODULE_DEVICE_TABLE(of, lpc18xx_rgu_match);
245*c392b65bSJoachim Eastwood 
246*c392b65bSJoachim Eastwood static struct platform_driver lpc18xx_rgu_driver = {
247*c392b65bSJoachim Eastwood 	.probe	= lpc18xx_rgu_probe,
248*c392b65bSJoachim Eastwood 	.remove	= lpc18xx_rgu_remove,
249*c392b65bSJoachim Eastwood 	.driver	= {
250*c392b65bSJoachim Eastwood 		.name		= "lpc18xx-reset",
251*c392b65bSJoachim Eastwood 		.of_match_table	= lpc18xx_rgu_match,
252*c392b65bSJoachim Eastwood 	},
253*c392b65bSJoachim Eastwood };
254*c392b65bSJoachim Eastwood module_platform_driver(lpc18xx_rgu_driver);
255*c392b65bSJoachim Eastwood 
256*c392b65bSJoachim Eastwood MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
257*c392b65bSJoachim Eastwood MODULE_DESCRIPTION("Reset driver for LPC18xx/43xx RGU");
258*c392b65bSJoachim Eastwood MODULE_LICENSE("GPL v2");
259