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
,
92 * struct reset_simple_devdata - simple reset controller properties
93 * @reg_offset: offset between base address and first reset register.
94 * @nr_resets: number of resets. If not set, default to resource size in bits.
95 * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits
96 * are set to assert the reset.
97 * @status_active_low: if true, bits read back as cleared while the reset is
98 * asserted. Otherwise, bits read back as set while the
101 struct reset_simple_devdata
{
105 bool status_active_low
;
108 #define SOCFPGA_NR_BANKS 8
110 static const struct reset_simple_devdata reset_simple_socfpga
= {
112 .nr_resets
= SOCFPGA_NR_BANKS
* 32,
113 .status_active_low
= true,
116 static const struct reset_simple_devdata reset_simple_active_low
= {
118 .status_active_low
= true,
121 static const struct of_device_id reset_simple_dt_ids
[] = {
122 { .compatible
= "altr,rst-mgr", .data
= &reset_simple_socfpga
},
123 { .compatible
= "st,stm32-rcc", },
124 { .compatible
= "allwinner,sun6i-a31-clock-reset",
125 .data
= &reset_simple_active_low
},
126 { .compatible
= "zte,zx296718-reset",
127 .data
= &reset_simple_active_low
},
128 { .compatible
= "aspeed,ast2400-lpc-reset" },
129 { .compatible
= "aspeed,ast2500-lpc-reset" },
133 static int reset_simple_probe(struct platform_device
*pdev
)
135 struct device
*dev
= &pdev
->dev
;
136 const struct reset_simple_devdata
*devdata
;
137 struct reset_simple_data
*data
;
138 void __iomem
*membase
;
139 struct resource
*res
;
142 devdata
= of_device_get_match_data(dev
);
144 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
148 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
149 membase
= devm_ioremap_resource(dev
, res
);
151 return PTR_ERR(membase
);
153 spin_lock_init(&data
->lock
);
154 data
->membase
= membase
;
155 data
->rcdev
.owner
= THIS_MODULE
;
156 data
->rcdev
.nr_resets
= resource_size(res
) * BITS_PER_BYTE
;
157 data
->rcdev
.ops
= &reset_simple_ops
;
158 data
->rcdev
.of_node
= dev
->of_node
;
161 reg_offset
= devdata
->reg_offset
;
162 if (devdata
->nr_resets
)
163 data
->rcdev
.nr_resets
= devdata
->nr_resets
;
164 data
->active_low
= devdata
->active_low
;
165 data
->status_active_low
= devdata
->status_active_low
;
168 if (of_device_is_compatible(dev
->of_node
, "altr,rst-mgr") &&
169 of_property_read_u32(dev
->of_node
, "altr,modrst-offset",
172 "missing altr,modrst-offset property, assuming 0x%x!\n",
176 data
->membase
+= reg_offset
;
178 return devm_reset_controller_register(dev
, &data
->rcdev
);
181 static struct platform_driver reset_simple_driver
= {
182 .probe
= reset_simple_probe
,
184 .name
= "simple-reset",
185 .of_match_table
= reset_simple_dt_ids
,
188 builtin_platform_driver(reset_simple_driver
);