1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Simple Reset Controller Driver
5 * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
7 * Based on Allwinner SoCs Reset Controller driver
9 * Copyright 2013 Maxime Ripard
11 * Maxime Ripard <maxime.ripard@free-electrons.com>
14 #include <linux/delay.h>
15 #include <linux/device.h>
16 #include <linux/err.h>
19 #include <linux/platform_device.h>
20 #include <linux/reset-controller.h>
21 #include <linux/reset/reset-simple.h>
22 #include <linux/spinlock.h>
24 static inline struct reset_simple_data
*
25 to_reset_simple_data(struct reset_controller_dev
*rcdev
)
27 return container_of(rcdev
, struct reset_simple_data
, rcdev
);
30 static int reset_simple_update(struct reset_controller_dev
*rcdev
,
31 unsigned long id
, bool assert)
33 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
34 int reg_width
= sizeof(u32
);
35 int bank
= id
/ (reg_width
* BITS_PER_BYTE
);
36 int offset
= id
% (reg_width
* BITS_PER_BYTE
);
40 spin_lock_irqsave(&data
->lock
, flags
);
42 reg
= readl(data
->membase
+ (bank
* reg_width
));
43 if (assert ^ data
->active_low
)
47 writel(reg
, data
->membase
+ (bank
* reg_width
));
49 spin_unlock_irqrestore(&data
->lock
, flags
);
54 static int reset_simple_assert(struct reset_controller_dev
*rcdev
,
57 return reset_simple_update(rcdev
, id
, true);
60 static int reset_simple_deassert(struct reset_controller_dev
*rcdev
,
63 return reset_simple_update(rcdev
, id
, false);
66 static int reset_simple_reset(struct reset_controller_dev
*rcdev
,
69 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
75 ret
= reset_simple_assert(rcdev
, id
);
79 usleep_range(data
->reset_us
, data
->reset_us
* 2);
81 return reset_simple_deassert(rcdev
, id
);
84 static int reset_simple_status(struct reset_controller_dev
*rcdev
,
87 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
88 int reg_width
= sizeof(u32
);
89 int bank
= id
/ (reg_width
* BITS_PER_BYTE
);
90 int offset
= id
% (reg_width
* BITS_PER_BYTE
);
93 reg
= readl(data
->membase
+ (bank
* reg_width
));
95 return !(reg
& BIT(offset
)) ^ !data
->status_active_low
;
98 const struct reset_control_ops reset_simple_ops
= {
99 .assert = reset_simple_assert
,
100 .deassert
= reset_simple_deassert
,
101 .reset
= reset_simple_reset
,
102 .status
= reset_simple_status
,
104 EXPORT_SYMBOL_GPL(reset_simple_ops
);
107 * struct reset_simple_devdata - simple reset controller properties
108 * @reg_offset: offset between base address and first reset register.
109 * @nr_resets: number of resets. If not set, default to resource size in bits.
110 * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits
111 * are set to assert the reset.
112 * @status_active_low: if true, bits read back as cleared while the reset is
113 * asserted. Otherwise, bits read back as set while the
116 struct reset_simple_devdata
{
120 bool status_active_low
;
123 #define SOCFPGA_NR_BANKS 8
125 static const struct reset_simple_devdata reset_simple_socfpga
= {
127 .nr_resets
= SOCFPGA_NR_BANKS
* 32,
128 .status_active_low
= true,
131 static const struct reset_simple_devdata reset_simple_active_low
= {
133 .status_active_low
= true,
136 static const struct of_device_id reset_simple_dt_ids
[] = {
137 { .compatible
= "altr,stratix10-rst-mgr",
138 .data
= &reset_simple_socfpga
},
139 { .compatible
= "st,stm32-rcc", },
140 { .compatible
= "allwinner,sun6i-a31-clock-reset",
141 .data
= &reset_simple_active_low
},
142 { .compatible
= "zte,zx296718-reset",
143 .data
= &reset_simple_active_low
},
144 { .compatible
= "aspeed,ast2400-lpc-reset" },
145 { .compatible
= "aspeed,ast2500-lpc-reset" },
146 { .compatible
= "aspeed,ast2600-lpc-reset" },
147 { .compatible
= "bitmain,bm1880-reset",
148 .data
= &reset_simple_active_low
},
149 { .compatible
= "brcm,bcm4908-misc-pcie-reset",
150 .data
= &reset_simple_active_low
},
151 { .compatible
= "snps,dw-high-reset" },
152 { .compatible
= "snps,dw-low-reset",
153 .data
= &reset_simple_active_low
},
154 { .compatible
= "sophgo,sg2042-reset",
155 .data
= &reset_simple_active_low
},
159 static int reset_simple_probe(struct platform_device
*pdev
)
161 struct device
*dev
= &pdev
->dev
;
162 const struct reset_simple_devdata
*devdata
;
163 struct reset_simple_data
*data
;
164 void __iomem
*membase
;
165 struct resource
*res
;
168 devdata
= of_device_get_match_data(dev
);
170 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
174 membase
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
176 return PTR_ERR(membase
);
178 spin_lock_init(&data
->lock
);
179 data
->membase
= membase
;
180 data
->rcdev
.owner
= THIS_MODULE
;
181 data
->rcdev
.nr_resets
= resource_size(res
) * BITS_PER_BYTE
;
182 data
->rcdev
.ops
= &reset_simple_ops
;
183 data
->rcdev
.of_node
= dev
->of_node
;
186 reg_offset
= devdata
->reg_offset
;
187 if (devdata
->nr_resets
)
188 data
->rcdev
.nr_resets
= devdata
->nr_resets
;
189 data
->active_low
= devdata
->active_low
;
190 data
->status_active_low
= devdata
->status_active_low
;
193 data
->membase
+= reg_offset
;
195 return devm_reset_controller_register(dev
, &data
->rcdev
);
198 static struct platform_driver reset_simple_driver
= {
199 .probe
= reset_simple_probe
,
201 .name
= "simple-reset",
202 .of_match_table
= reset_simple_dt_ids
,
205 builtin_platform_driver(reset_simple_driver
);