diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-01 16:00:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-01 16:00:04 -0400 |
commit | 102178108e2246cb4b329d3fb7872cd3d7120205 (patch) | |
tree | 3c0720bd96e613631d3983bba385fc675dceb08e /drivers/reset/reset-zynq.c | |
parent | 50686e8a3aed2f5d295e9d2e79ff43df461c7b76 (diff) | |
parent | 21815b9a24c6e6d3488703609561bd2892d3d9f3 (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.c | 155 |
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 | |||
26 | struct 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 | |||
35 | static 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 | |||
52 | static 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 | |||
69 | static 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), ®); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | |||
86 | return !!(reg & BIT(offset)); | ||
87 | } | ||
88 | |||
89 | static struct reset_control_ops zynq_reset_ops = { | ||
90 | .assert = zynq_reset_assert, | ||
91 | .deassert = zynq_reset_deassert, | ||
92 | .status = zynq_reset_status, | ||
93 | }; | ||
94 | |||
95 | static 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 | |||
129 | static 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 | |||
138 | static const struct of_device_id zynq_reset_dt_ids[] = { | ||
139 | { .compatible = "xlnx,zynq-reset", }, | ||
140 | { /* sentinel */ }, | ||
141 | }; | ||
142 | |||
143 | static 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 | }; | ||
151 | module_platform_driver(zynq_reset_driver); | ||
152 | |||
153 | MODULE_LICENSE("GPL v2"); | ||
154 | MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>"); | ||
155 | MODULE_DESCRIPTION("Zynq Reset Controller Driver"); | ||