2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
6 * Copyright (C) 2010 John Crispin <blogic@phrozen.org>
7 * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
8 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
9 * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/regmap.h>
15 #include <linux/reset-controller.h>
16 #include <linux/of_address.h>
17 #include <linux/of_platform.h>
18 #include <linux/platform_device.h>
19 #include <linux/property.h>
21 #define LANTIQ_RCU_RESET_TIMEOUT 10000
23 struct lantiq_rcu_reset_priv
{
24 struct reset_controller_dev rcdev
;
26 struct regmap
*regmap
;
31 static struct lantiq_rcu_reset_priv
*to_lantiq_rcu_reset_priv(
32 struct reset_controller_dev
*rcdev
)
34 return container_of(rcdev
, struct lantiq_rcu_reset_priv
, rcdev
);
37 static int lantiq_rcu_reset_status(struct reset_controller_dev
*rcdev
,
40 struct lantiq_rcu_reset_priv
*priv
= to_lantiq_rcu_reset_priv(rcdev
);
41 unsigned int status
= (id
>> 8) & 0x1f;
45 ret
= regmap_read(priv
->regmap
, priv
->status_offset
, &val
);
49 return !!(val
& BIT(status
));
52 static int lantiq_rcu_reset_status_timeout(struct reset_controller_dev
*rcdev
,
53 unsigned long id
, bool assert)
56 int retry
= LANTIQ_RCU_RESET_TIMEOUT
;
59 ret
= lantiq_rcu_reset_status(rcdev
, id
);
70 static int lantiq_rcu_reset_update(struct reset_controller_dev
*rcdev
,
71 unsigned long id
, bool assert)
73 struct lantiq_rcu_reset_priv
*priv
= to_lantiq_rcu_reset_priv(rcdev
);
74 unsigned int set
= id
& 0x1f;
75 u32 val
= assert ? BIT(set
) : 0;
78 ret
= regmap_update_bits(priv
->regmap
, priv
->reset_offset
, BIT(set
),
81 dev_err(priv
->dev
, "Failed to set reset bit %u\n", set
);
86 ret
= lantiq_rcu_reset_status_timeout(rcdev
, id
, assert);
88 dev_err(priv
->dev
, "Failed to %s bit %u\n",
89 assert ? "assert" : "deassert", set
);
94 static int lantiq_rcu_reset_assert(struct reset_controller_dev
*rcdev
,
97 return lantiq_rcu_reset_update(rcdev
, id
, true);
100 static int lantiq_rcu_reset_deassert(struct reset_controller_dev
*rcdev
,
103 return lantiq_rcu_reset_update(rcdev
, id
, false);
106 static int lantiq_rcu_reset_reset(struct reset_controller_dev
*rcdev
,
111 ret
= lantiq_rcu_reset_assert(rcdev
, id
);
115 return lantiq_rcu_reset_deassert(rcdev
, id
);
118 static const struct reset_control_ops lantiq_rcu_reset_ops
= {
119 .assert = lantiq_rcu_reset_assert
,
120 .deassert
= lantiq_rcu_reset_deassert
,
121 .status
= lantiq_rcu_reset_status
,
122 .reset
= lantiq_rcu_reset_reset
,
125 static int lantiq_rcu_reset_of_parse(struct platform_device
*pdev
,
126 struct lantiq_rcu_reset_priv
*priv
)
128 struct device
*dev
= &pdev
->dev
;
129 const __be32
*offset
;
131 priv
->regmap
= syscon_node_to_regmap(dev
->of_node
->parent
);
132 if (IS_ERR(priv
->regmap
)) {
133 dev_err(&pdev
->dev
, "Failed to lookup RCU regmap\n");
134 return PTR_ERR(priv
->regmap
);
137 offset
= of_get_address(dev
->of_node
, 0, NULL
, NULL
);
139 dev_err(&pdev
->dev
, "Failed to get RCU reset offset\n");
142 priv
->reset_offset
= __be32_to_cpu(*offset
);
144 offset
= of_get_address(dev
->of_node
, 1, NULL
, NULL
);
146 dev_err(&pdev
->dev
, "Failed to get RCU status offset\n");
149 priv
->status_offset
= __be32_to_cpu(*offset
);
154 static int lantiq_rcu_reset_xlate(struct reset_controller_dev
*rcdev
,
155 const struct of_phandle_args
*reset_spec
)
157 unsigned int status
, set
;
159 set
= reset_spec
->args
[0];
160 status
= reset_spec
->args
[1];
162 if (set
>= rcdev
->nr_resets
|| status
>= rcdev
->nr_resets
)
165 return (status
<< 8) | set
;
168 static int lantiq_rcu_reset_probe(struct platform_device
*pdev
)
170 struct lantiq_rcu_reset_priv
*priv
;
173 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
177 priv
->dev
= &pdev
->dev
;
178 platform_set_drvdata(pdev
, priv
);
180 err
= lantiq_rcu_reset_of_parse(pdev
, priv
);
184 priv
->rcdev
.ops
= &lantiq_rcu_reset_ops
;
185 priv
->rcdev
.owner
= THIS_MODULE
;
186 priv
->rcdev
.of_node
= pdev
->dev
.of_node
;
187 priv
->rcdev
.nr_resets
= 32;
188 priv
->rcdev
.of_xlate
= lantiq_rcu_reset_xlate
;
189 priv
->rcdev
.of_reset_n_cells
= 2;
191 return reset_controller_register(&priv
->rcdev
);
194 static const struct of_device_id lantiq_rcu_reset_dt_ids
[] = {
195 { .compatible
= "lantiq,danube-reset", },
196 { .compatible
= "lantiq,xrx200-reset", },
199 MODULE_DEVICE_TABLE(of
, lantiq_rcu_reset_dt_ids
);
201 static struct platform_driver lantiq_rcu_reset_driver
= {
202 .probe
= lantiq_rcu_reset_probe
,
204 .name
= "lantiq-reset",
205 .of_match_table
= lantiq_rcu_reset_dt_ids
,
208 module_platform_driver(lantiq_rcu_reset_driver
);
210 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
211 MODULE_DESCRIPTION("Lantiq XWAY RCU Reset Controller Driver");
212 MODULE_LICENSE("GPL");