2 * Copyright (c) 2015, National Instruments Corp.
4 * Xilinx Zynq Reset controller driver
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/err.h>
18 #include <linux/module.h>
19 #include <linux/mfd/syscon.h>
21 #include <linux/platform_device.h>
22 #include <linux/reset-controller.h>
23 #include <linux/regmap.h>
24 #include <linux/types.h>
26 struct zynq_reset_data
{
28 struct reset_controller_dev rcdev
;
32 #define to_zynq_reset_data(p) \
33 container_of((p), struct zynq_reset_data, rcdev)
35 static int zynq_reset_assert(struct reset_controller_dev
*rcdev
,
38 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
40 int bank
= id
/ BITS_PER_LONG
;
41 int offset
= id
% BITS_PER_LONG
;
43 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
46 return regmap_update_bits(priv
->slcr
,
47 priv
->offset
+ (bank
* 4),
52 static int zynq_reset_deassert(struct reset_controller_dev
*rcdev
,
55 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
57 int bank
= id
/ BITS_PER_LONG
;
58 int offset
= id
% BITS_PER_LONG
;
60 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
63 return regmap_update_bits(priv
->slcr
,
64 priv
->offset
+ (bank
* 4),
69 static int zynq_reset_status(struct reset_controller_dev
*rcdev
,
72 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
74 int bank
= id
/ BITS_PER_LONG
;
75 int offset
= id
% BITS_PER_LONG
;
79 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
82 ret
= regmap_read(priv
->slcr
, priv
->offset
+ (bank
* 4), ®
);
86 return !!(reg
& BIT(offset
));
89 static const struct reset_control_ops zynq_reset_ops
= {
90 .assert = zynq_reset_assert
,
91 .deassert
= zynq_reset_deassert
,
92 .status
= zynq_reset_status
,
95 static int zynq_reset_probe(struct platform_device
*pdev
)
98 struct zynq_reset_data
*priv
;
100 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
103 platform_set_drvdata(pdev
, priv
);
105 priv
->slcr
= syscon_regmap_lookup_by_phandle(pdev
->dev
.of_node
,
107 if (IS_ERR(priv
->slcr
)) {
108 dev_err(&pdev
->dev
, "unable to get zynq-slcr regmap");
109 return PTR_ERR(priv
->slcr
);
112 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
114 dev_err(&pdev
->dev
, "missing IO resource\n");
118 priv
->offset
= res
->start
;
120 priv
->rcdev
.owner
= THIS_MODULE
;
121 priv
->rcdev
.nr_resets
= resource_size(res
) / 4 * BITS_PER_LONG
;
122 priv
->rcdev
.ops
= &zynq_reset_ops
;
123 priv
->rcdev
.of_node
= pdev
->dev
.of_node
;
125 return reset_controller_register(&priv
->rcdev
);
128 static int zynq_reset_remove(struct platform_device
*pdev
)
130 struct zynq_reset_data
*priv
= platform_get_drvdata(pdev
);
132 reset_controller_unregister(&priv
->rcdev
);
137 static const struct of_device_id zynq_reset_dt_ids
[] = {
138 { .compatible
= "xlnx,zynq-reset", },
142 static struct platform_driver zynq_reset_driver
= {
143 .probe
= zynq_reset_probe
,
144 .remove
= zynq_reset_remove
,
146 .name
= KBUILD_MODNAME
,
147 .of_match_table
= zynq_reset_dt_ids
,
150 module_platform_driver(zynq_reset_driver
);
152 MODULE_LICENSE("GPL v2");
153 MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>");
154 MODULE_DESCRIPTION("Zynq Reset Controller Driver");