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/device.h>
15 #include <linux/err.h>
18 #include <linux/of_device.h>
19 #include <linux/platform_device.h>
20 #include <linux/reset-controller.h>
21 #include <linux/spinlock.h>
23 #include "reset-simple.h"
25 static inline struct reset_simple_data
*
26 to_reset_simple_data(struct reset_controller_dev
*rcdev
)
28 return container_of(rcdev
, struct reset_simple_data
, rcdev
);
31 static int reset_simple_update(struct reset_controller_dev
*rcdev
,
32 unsigned long id
, bool assert)
34 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
35 int reg_width
= sizeof(u32
);
36 int bank
= id
/ (reg_width
* BITS_PER_BYTE
);
37 int offset
= id
% (reg_width
* BITS_PER_BYTE
);
41 spin_lock_irqsave(&data
->lock
, flags
);
43 reg
= readl(data
->membase
+ (bank
* reg_width
));
44 if (assert ^ data
->active_low
)
48 writel(reg
, data
->membase
+ (bank
* reg_width
));
50 spin_unlock_irqrestore(&data
->lock
, flags
);
55 static int reset_simple_assert(struct reset_controller_dev
*rcdev
,
58 return reset_simple_update(rcdev
, id
, true);
61 static int reset_simple_deassert(struct reset_controller_dev
*rcdev
,
64 return reset_simple_update(rcdev
, id
, false);
67 static int reset_simple_status(struct reset_controller_dev
*rcdev
,
70 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
71 int reg_width
= sizeof(u32
);
72 int bank
= id
/ (reg_width
* BITS_PER_BYTE
);
73 int offset
= id
% (reg_width
* BITS_PER_BYTE
);
76 reg
= readl(data
->membase
+ (bank
* reg_width
));
78 return !(reg
& BIT(offset
)) ^ !data
->status_active_low
;
81 const struct reset_control_ops reset_simple_ops
= {
82 .assert = reset_simple_assert
,
83 .deassert
= reset_simple_deassert
,
84 .status
= reset_simple_status
,
86 EXPORT_SYMBOL_GPL(reset_simple_ops
);
89 * struct reset_simple_devdata - simple reset controller properties
90 * @reg_offset: offset between base address and first reset register.
91 * @nr_resets: number of resets. If not set, default to resource size in bits.
92 * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits
93 * are set to assert the reset.
94 * @status_active_low: if true, bits read back as cleared while the reset is
95 * asserted. Otherwise, bits read back as set while the
98 struct reset_simple_devdata
{
102 bool status_active_low
;
105 #define SOCFPGA_NR_BANKS 8
107 static const struct reset_simple_devdata reset_simple_socfpga
= {
109 .nr_resets
= SOCFPGA_NR_BANKS
* 32,
110 .status_active_low
= true,
113 static const struct reset_simple_devdata reset_simple_active_low
= {
115 .status_active_low
= true,
118 static const struct of_device_id reset_simple_dt_ids
[] = {
119 { .compatible
= "altr,stratix10-rst-mgr",
120 .data
= &reset_simple_socfpga
},
121 { .compatible
= "st,stm32-rcc", },
122 { .compatible
= "allwinner,sun6i-a31-clock-reset",
123 .data
= &reset_simple_active_low
},
124 { .compatible
= "zte,zx296718-reset",
125 .data
= &reset_simple_active_low
},
126 { .compatible
= "aspeed,ast2400-lpc-reset" },
127 { .compatible
= "aspeed,ast2500-lpc-reset" },
128 { .compatible
= "bitmain,bm1880-reset",
129 .data
= &reset_simple_active_low
},
130 { .compatible
= "snps,dw-high-reset" },
131 { .compatible
= "snps,dw-low-reset",
132 .data
= &reset_simple_active_low
},
136 static int reset_simple_probe(struct platform_device
*pdev
)
138 struct device
*dev
= &pdev
->dev
;
139 const struct reset_simple_devdata
*devdata
;
140 struct reset_simple_data
*data
;
141 void __iomem
*membase
;
142 struct resource
*res
;
145 devdata
= of_device_get_match_data(dev
);
147 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
151 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
152 membase
= devm_ioremap_resource(dev
, res
);
154 return PTR_ERR(membase
);
156 spin_lock_init(&data
->lock
);
157 data
->membase
= membase
;
158 data
->rcdev
.owner
= THIS_MODULE
;
159 data
->rcdev
.nr_resets
= resource_size(res
) * BITS_PER_BYTE
;
160 data
->rcdev
.ops
= &reset_simple_ops
;
161 data
->rcdev
.of_node
= dev
->of_node
;
164 reg_offset
= devdata
->reg_offset
;
165 if (devdata
->nr_resets
)
166 data
->rcdev
.nr_resets
= devdata
->nr_resets
;
167 data
->active_low
= devdata
->active_low
;
168 data
->status_active_low
= devdata
->status_active_low
;
171 data
->membase
+= reg_offset
;
173 return devm_reset_controller_register(dev
, &data
->rcdev
);
176 static struct platform_driver reset_simple_driver
= {
177 .probe
= reset_simple_probe
,
179 .name
= "simple-reset",
180 .of_match_table
= reset_simple_dt_ids
,
183 builtin_platform_driver(reset_simple_driver
);