1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2015, National Instruments Corp.
5 * Xilinx Zynq Reset controller driver
7 * Author: Moritz Fischer <moritz.fischer@ettus.com>
10 #include <linux/err.h>
12 #include <linux/init.h>
13 #include <linux/mfd/syscon.h>
15 #include <linux/platform_device.h>
16 #include <linux/reset-controller.h>
17 #include <linux/regmap.h>
18 #include <linux/types.h>
20 struct zynq_reset_data
{
22 struct reset_controller_dev rcdev
;
26 #define to_zynq_reset_data(p) \
27 container_of((p), struct zynq_reset_data, rcdev)
29 static int zynq_reset_assert(struct reset_controller_dev
*rcdev
,
32 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
34 int bank
= id
/ BITS_PER_LONG
;
35 int offset
= id
% BITS_PER_LONG
;
37 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
40 return regmap_update_bits(priv
->slcr
,
41 priv
->offset
+ (bank
* 4),
46 static int zynq_reset_deassert(struct reset_controller_dev
*rcdev
,
49 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
51 int bank
= id
/ BITS_PER_LONG
;
52 int offset
= id
% BITS_PER_LONG
;
54 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
57 return regmap_update_bits(priv
->slcr
,
58 priv
->offset
+ (bank
* 4),
63 static int zynq_reset_status(struct reset_controller_dev
*rcdev
,
66 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
68 int bank
= id
/ BITS_PER_LONG
;
69 int offset
= id
% BITS_PER_LONG
;
73 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
76 ret
= regmap_read(priv
->slcr
, priv
->offset
+ (bank
* 4), ®
);
80 return !!(reg
& BIT(offset
));
83 static const struct reset_control_ops zynq_reset_ops
= {
84 .assert = zynq_reset_assert
,
85 .deassert
= zynq_reset_deassert
,
86 .status
= zynq_reset_status
,
89 static int zynq_reset_probe(struct platform_device
*pdev
)
92 struct zynq_reset_data
*priv
;
94 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
97 platform_set_drvdata(pdev
, priv
);
99 priv
->slcr
= syscon_regmap_lookup_by_phandle(pdev
->dev
.of_node
,
101 if (IS_ERR(priv
->slcr
)) {
102 dev_err(&pdev
->dev
, "unable to get zynq-slcr regmap");
103 return PTR_ERR(priv
->slcr
);
106 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
108 dev_err(&pdev
->dev
, "missing IO resource\n");
112 priv
->offset
= res
->start
;
114 priv
->rcdev
.owner
= THIS_MODULE
;
115 priv
->rcdev
.nr_resets
= resource_size(res
) / 4 * BITS_PER_LONG
;
116 priv
->rcdev
.ops
= &zynq_reset_ops
;
117 priv
->rcdev
.of_node
= pdev
->dev
.of_node
;
119 return devm_reset_controller_register(&pdev
->dev
, &priv
->rcdev
);
122 static const struct of_device_id zynq_reset_dt_ids
[] = {
123 { .compatible
= "xlnx,zynq-reset", },
127 static struct platform_driver zynq_reset_driver
= {
128 .probe
= zynq_reset_probe
,
130 .name
= KBUILD_MODNAME
,
131 .of_match_table
= zynq_reset_dt_ids
,
134 builtin_platform_driver(zynq_reset_driver
);