2 * Simple Reset Controller Driver
4 * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
6 * Based on Allwinner SoCs Reset Controller driver
8 * Copyright 2013 Maxime Ripard
10 * Maxime Ripard <maxime.ripard@free-electrons.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
18 #include <linux/device.h>
19 #include <linux/err.h>
22 #include <linux/of_device.h>
23 #include <linux/platform_device.h>
24 #include <linux/reset-controller.h>
25 #include <linux/spinlock.h>
27 #include "reset-simple.h"
29 static inline struct reset_simple_data
*
30 to_reset_simple_data(struct reset_controller_dev
*rcdev
)
32 return container_of(rcdev
, struct reset_simple_data
, rcdev
);
35 static int reset_simple_update(struct reset_controller_dev
*rcdev
,
36 unsigned long id
, bool assert)
38 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
39 int reg_width
= sizeof(u32
);
40 int bank
= id
/ (reg_width
* BITS_PER_BYTE
);
41 int offset
= id
% (reg_width
* BITS_PER_BYTE
);
45 spin_lock_irqsave(&data
->lock
, flags
);
47 reg
= readl(data
->membase
+ (bank
* reg_width
));
48 if (assert ^ data
->active_low
)
52 writel(reg
, data
->membase
+ (bank
* reg_width
));
54 spin_unlock_irqrestore(&data
->lock
, flags
);
59 static int reset_simple_assert(struct reset_controller_dev
*rcdev
,
62 return reset_simple_update(rcdev
, id
, true);
65 static int reset_simple_deassert(struct reset_controller_dev
*rcdev
,
68 return reset_simple_update(rcdev
, id
, false);
71 static int reset_simple_status(struct reset_controller_dev
*rcdev
,
74 struct reset_simple_data
*data
= to_reset_simple_data(rcdev
);
75 int reg_width
= sizeof(u32
);
76 int bank
= id
/ (reg_width
* BITS_PER_BYTE
);
77 int offset
= id
% (reg_width
* BITS_PER_BYTE
);
80 reg
= readl(data
->membase
+ (bank
* reg_width
));
82 return !(reg
& BIT(offset
)) ^ !data
->status_active_low
;
85 const struct reset_control_ops reset_simple_ops
= {
86 .assert = reset_simple_assert
,
87 .deassert
= reset_simple_deassert
,
88 .status
= reset_simple_status
,
90 EXPORT_SYMBOL_GPL(reset_simple_ops
);
93 * struct reset_simple_devdata - simple reset controller properties
94 * @reg_offset: offset between base address and first reset register.
95 * @nr_resets: number of resets. If not set, default to resource size in bits.
96 * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits
97 * are set to assert the reset.
98 * @status_active_low: if true, bits read back as cleared while the reset is
99 * asserted. Otherwise, bits read back as set while the
102 struct reset_simple_devdata
{
106 bool status_active_low
;
109 #define SOCFPGA_NR_BANKS 8
111 static const struct reset_simple_devdata reset_simple_socfpga
= {
113 .nr_resets
= SOCFPGA_NR_BANKS
* 32,
114 .status_active_low
= true,
117 static const struct reset_simple_devdata reset_simple_active_low
= {
119 .status_active_low
= true,
122 static const struct of_device_id reset_simple_dt_ids
[] = {
123 { .compatible
= "altr,rst-mgr", .data
= &reset_simple_socfpga
},
124 { .compatible
= "st,stm32-rcc", },
125 { .compatible
= "allwinner,sun6i-a31-clock-reset",
126 .data
= &reset_simple_active_low
},
127 { .compatible
= "zte,zx296718-reset",
128 .data
= &reset_simple_active_low
},
129 { .compatible
= "aspeed,ast2400-lpc-reset" },
130 { .compatible
= "aspeed,ast2500-lpc-reset" },
134 static int reset_simple_probe(struct platform_device
*pdev
)
136 struct device
*dev
= &pdev
->dev
;
137 const struct reset_simple_devdata
*devdata
;
138 struct reset_simple_data
*data
;
139 void __iomem
*membase
;
140 struct resource
*res
;
143 devdata
= of_device_get_match_data(dev
);
145 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
149 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
150 membase
= devm_ioremap_resource(dev
, res
);
152 return PTR_ERR(membase
);
154 spin_lock_init(&data
->lock
);
155 data
->membase
= membase
;
156 data
->rcdev
.owner
= THIS_MODULE
;
157 data
->rcdev
.nr_resets
= resource_size(res
) * BITS_PER_BYTE
;
158 data
->rcdev
.ops
= &reset_simple_ops
;
159 data
->rcdev
.of_node
= dev
->of_node
;
162 reg_offset
= devdata
->reg_offset
;
163 if (devdata
->nr_resets
)
164 data
->rcdev
.nr_resets
= devdata
->nr_resets
;
165 data
->active_low
= devdata
->active_low
;
166 data
->status_active_low
= devdata
->status_active_low
;
169 if (of_device_is_compatible(dev
->of_node
, "altr,rst-mgr") &&
170 of_property_read_u32(dev
->of_node
, "altr,modrst-offset",
173 "missing altr,modrst-offset property, assuming 0x%x!\n",
177 data
->membase
+= reg_offset
;
179 return devm_reset_controller_register(dev
, &data
->rcdev
);
182 static struct platform_driver reset_simple_driver
= {
183 .probe
= reset_simple_probe
,
185 .name
= "simple-reset",
186 .of_match_table
= reset_simple_dt_ids
,
189 builtin_platform_driver(reset_simple_driver
);