aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/reset/reset-zynq.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-09-01 16:00:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-01 16:00:04 -0400
commit102178108e2246cb4b329d3fb7872cd3d7120205 (patch)
tree3c0720bd96e613631d3983bba385fc675dceb08e /drivers/reset/reset-zynq.c
parent50686e8a3aed2f5d295e9d2e79ff43df461c7b76 (diff)
parent21815b9a24c6e6d3488703609561bd2892d3d9f3 (diff)
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson: "Some releases this branch is nearly empty, others we have more stuff. It tends to gather drivers that need SoC modification or dependencies such that they have to (also) go in through our tree. For this release, we have merged in part of the reset controller tree (with handshake that the parts we have merged in will remain stable), as well as dependencies on a few clock branches. In general, new items here are: - Qualcomm driver for SMM/SMD, which is how they communicate with the coprocessors on (some) of their platforms - memory controller work for ARM's PL172 memory controller - reset drivers for various platforms - PMU power domain support for Marvell platforms - Tegra support for T132/T210 SoCs: PMC, fuse, memory controller per-SoC support" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (49 commits) ARM: tegra: cpuidle: implement cpuidle_state.enter_freeze() ARM: tegra: Disable cpuidle if PSCI is available soc/tegra: pmc: Use existing pclk reference soc/tegra: pmc: Remove unnecessary return statement soc: tegra: Remove redundant $(CONFIG_ARCH_TEGRA) in Makefile memory: tegra: Add Tegra210 support memory: tegra: Add support for a variable-size client ID bitfield clk: shmobile: rz: Add CPG/MSTP Clock Domain support clk: shmobile: rcar-gen2: Add CPG/MSTP Clock Domain support clk: shmobile: r8a7779: Add CPG/MSTP Clock Domain support clk: shmobile: r8a7778: Add CPG/MSTP Clock Domain support clk: shmobile: Add CPG/MSTP Clock Domain support ARM: dove: create a proper PMU driver for power domains, PMU IRQs and resets reset: reset-zynq: Adding support for Xilinx Zynq reset controller. docs: dts: Added documentation for Xilinx Zynq Reset Controller bindings. MIPS: ath79: Add the reset controller to the AR9132 dtsi reset: Add a driver for the reset controller on the AR71XX/AR9XXX devicetree: Add bindings for the ATH79 reset controller reset: socfpga: Update reset-socfpga to read the altr,modrst-offset property doc: dt: add documentation for lpc1850-rgu reset driver ...
Diffstat (limited to 'drivers/reset/reset-zynq.c')
-rw-r--r--drivers/reset/reset-zynq.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/drivers/reset/reset-zynq.c b/drivers/reset/reset-zynq.c
new file mode 100644
index 000000000000..89318a5d5bd7
--- /dev/null
+++ b/drivers/reset/reset-zynq.c
@@ -0,0 +1,155 @@
1/*
2 * Copyright (c) 2015, National Instruments Corp.
3 *
4 * Xilinx Zynq Reset controller driver
5 *
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.
9 *
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.
14 */
15
16#include <linux/err.h>
17#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/mfd/syscon.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/reset-controller.h>
23#include <linux/regmap.h>
24#include <linux/types.h>
25
26struct zynq_reset_data {
27 struct regmap *slcr;
28 struct reset_controller_dev rcdev;
29 u32 offset;
30};
31
32#define to_zynq_reset_data(p) \
33 container_of((p), struct zynq_reset_data, rcdev)
34
35static int zynq_reset_assert(struct reset_controller_dev *rcdev,
36 unsigned long id)
37{
38 struct zynq_reset_data *priv = to_zynq_reset_data(rcdev);
39
40 int bank = id / BITS_PER_LONG;
41 int offset = id % BITS_PER_LONG;
42
43 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__,
44 bank, offset);
45
46 return regmap_update_bits(priv->slcr,
47 priv->offset + (bank * 4),
48 BIT(offset),
49 BIT(offset));
50}
51
52static int zynq_reset_deassert(struct reset_controller_dev *rcdev,
53 unsigned long id)
54{
55 struct zynq_reset_data *priv = to_zynq_reset_data(rcdev);
56
57 int bank = id / BITS_PER_LONG;
58 int offset = id % BITS_PER_LONG;
59
60 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__,
61 bank, offset);
62
63 return regmap_update_bits(priv->slcr,
64 priv->offset + (bank * 4),
65 BIT(offset),
66 ~BIT(offset));
67}
68
69static int zynq_reset_status(struct reset_controller_dev *rcdev,
70 unsigned long id)
71{
72 struct zynq_reset_data *priv = to_zynq_reset_data(rcdev);
73
74 int bank = id / BITS_PER_LONG;
75 int offset = id % BITS_PER_LONG;
76 int ret;
77 u32 reg;
78
79 pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__,
80 bank, offset);
81
82 ret = regmap_read(priv->slcr, priv->offset + (bank * 4), &reg);
83 if (ret)
84 return ret;
85
86 return !!(reg & BIT(offset));
87}
88
89static struct reset_control_ops zynq_reset_ops = {
90 .assert = zynq_reset_assert,
91 .deassert = zynq_reset_deassert,
92 .status = zynq_reset_status,
93};
94
95static int zynq_reset_probe(struct platform_device *pdev)
96{
97 struct resource *res;
98 struct zynq_reset_data *priv;
99
100 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
101 if (!priv)
102 return -ENOMEM;
103 platform_set_drvdata(pdev, priv);
104
105 priv->slcr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
106 "syscon");
107 if (IS_ERR(priv->slcr)) {
108 dev_err(&pdev->dev, "unable to get zynq-slcr regmap");
109 return PTR_ERR(priv->slcr);
110 }
111
112 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
113 if (!res) {
114 dev_err(&pdev->dev, "missing IO resource\n");
115 return -ENODEV;
116 }
117
118 priv->offset = res->start;
119
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;
124 reset_controller_register(&priv->rcdev);
125
126 return 0;
127}
128
129static int zynq_reset_remove(struct platform_device *pdev)
130{
131 struct zynq_reset_data *priv = platform_get_drvdata(pdev);
132
133 reset_controller_unregister(&priv->rcdev);
134
135 return 0;
136}
137
138static const struct of_device_id zynq_reset_dt_ids[] = {
139 { .compatible = "xlnx,zynq-reset", },
140 { /* sentinel */ },
141};
142
143static struct platform_driver zynq_reset_driver = {
144 .probe = zynq_reset_probe,
145 .remove = zynq_reset_remove,
146 .driver = {
147 .name = KBUILD_MODNAME,
148 .of_match_table = zynq_reset_dt_ids,
149 },
150};
151module_platform_driver(zynq_reset_driver);
152
153MODULE_LICENSE("GPL v2");
154MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>");
155MODULE_DESCRIPTION("Zynq Reset Controller Driver");