2 * Copyright (c) 2015, National Instruments Corp.
4 * Xilinx Zynq Reset controller driver
6 * Author: Moritz Fischer <moritz.fischer@ettus.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #include <linux/err.h>
20 #include <linux/init.h>
21 #include <linux/mfd/syscon.h>
23 #include <linux/platform_device.h>
24 #include <linux/reset-controller.h>
25 #include <linux/regmap.h>
26 #include <linux/types.h>
28 struct zynq_reset_data
{
30 struct reset_controller_dev rcdev
;
34 #define to_zynq_reset_data(p) \
35 container_of((p), struct zynq_reset_data, rcdev)
37 static int zynq_reset_assert(struct reset_controller_dev
*rcdev
,
40 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
42 int bank
= id
/ BITS_PER_LONG
;
43 int offset
= id
% BITS_PER_LONG
;
45 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
48 return regmap_update_bits(priv
->slcr
,
49 priv
->offset
+ (bank
* 4),
54 static int zynq_reset_deassert(struct reset_controller_dev
*rcdev
,
57 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
59 int bank
= id
/ BITS_PER_LONG
;
60 int offset
= id
% BITS_PER_LONG
;
62 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
65 return regmap_update_bits(priv
->slcr
,
66 priv
->offset
+ (bank
* 4),
71 static int zynq_reset_status(struct reset_controller_dev
*rcdev
,
74 struct zynq_reset_data
*priv
= to_zynq_reset_data(rcdev
);
76 int bank
= id
/ BITS_PER_LONG
;
77 int offset
= id
% BITS_PER_LONG
;
81 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME
, __func__
,
84 ret
= regmap_read(priv
->slcr
, priv
->offset
+ (bank
* 4), ®
);
88 return !!(reg
& BIT(offset
));
91 static const struct reset_control_ops zynq_reset_ops
= {
92 .assert = zynq_reset_assert
,
93 .deassert
= zynq_reset_deassert
,
94 .status
= zynq_reset_status
,
97 static int zynq_reset_probe(struct platform_device
*pdev
)
100 struct zynq_reset_data
*priv
;
102 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
105 platform_set_drvdata(pdev
, priv
);
107 priv
->slcr
= syscon_regmap_lookup_by_phandle(pdev
->dev
.of_node
,
109 if (IS_ERR(priv
->slcr
)) {
110 dev_err(&pdev
->dev
, "unable to get zynq-slcr regmap");
111 return PTR_ERR(priv
->slcr
);
114 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
116 dev_err(&pdev
->dev
, "missing IO resource\n");
120 priv
->offset
= res
->start
;
122 priv
->rcdev
.owner
= THIS_MODULE
;
123 priv
->rcdev
.nr_resets
= resource_size(res
) / 4 * BITS_PER_LONG
;
124 priv
->rcdev
.ops
= &zynq_reset_ops
;
125 priv
->rcdev
.of_node
= pdev
->dev
.of_node
;
127 return devm_reset_controller_register(&pdev
->dev
, &priv
->rcdev
);
130 static const struct of_device_id zynq_reset_dt_ids
[] = {
131 { .compatible
= "xlnx,zynq-reset", },
135 static struct platform_driver zynq_reset_driver
= {
136 .probe
= zynq_reset_probe
,
138 .name
= KBUILD_MODNAME
,
139 .of_match_table
= zynq_reset_dt_ids
,
142 builtin_platform_driver(zynq_reset_driver
);