diff options
author | Antoine Ténart <antoine.tenart@free-electrons.com> | 2014-09-03 03:48:20 -0400 |
---|---|---|
committer | Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | 2014-10-20 10:51:56 -0400 |
commit | bd13251f71fc86f06b344810835bc4e5e77edef7 (patch) | |
tree | 549c2849901c660bfbb25e17e6b7c33fc0c839ee /drivers/reset | |
parent | f114040e3ea6e07372334ade75d1ee0775c355e1 (diff) |
reset: add the Berlin reset controller driver
Add a reset controller for Marvell Berlin SoCs which is used by the
USB PHYs drivers (for now).
Signed-off-by: Antoine Ténart <antoine.tenart@free-electrons.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-berlin.c | 131 |
2 files changed, 132 insertions, 0 deletions
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 60fed3d7820b..157d421f755b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_RESET_CONTROLLER) += core.o | 1 | obj-$(CONFIG_RESET_CONTROLLER) += core.o |
2 | obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o | 2 | obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o |
3 | obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o | ||
3 | obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o | 4 | obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o |
4 | obj-$(CONFIG_ARCH_STI) += sti/ | 5 | obj-$(CONFIG_ARCH_STI) += sti/ |
diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c new file mode 100644 index 000000000000..f8b48a13cf0b --- /dev/null +++ b/drivers/reset/reset-berlin.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Marvell Technology Group Ltd. | ||
3 | * | ||
4 | * Antoine Tenart <antoine.tenart@free-electrons.com> | ||
5 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/delay.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/reset-controller.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/types.h> | ||
21 | |||
22 | #define BERLIN_MAX_RESETS 32 | ||
23 | |||
24 | #define to_berlin_reset_priv(p) \ | ||
25 | container_of((p), struct berlin_reset_priv, rcdev) | ||
26 | |||
27 | struct berlin_reset_priv { | ||
28 | void __iomem *base; | ||
29 | unsigned int size; | ||
30 | struct reset_controller_dev rcdev; | ||
31 | }; | ||
32 | |||
33 | static int berlin_reset_reset(struct reset_controller_dev *rcdev, | ||
34 | unsigned long id) | ||
35 | { | ||
36 | struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev); | ||
37 | int offset = id >> 8; | ||
38 | int mask = BIT(id & 0x1f); | ||
39 | |||
40 | writel(mask, priv->base + offset); | ||
41 | |||
42 | /* let the reset be effective */ | ||
43 | udelay(10); | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static struct reset_control_ops berlin_reset_ops = { | ||
49 | .reset = berlin_reset_reset, | ||
50 | }; | ||
51 | |||
52 | static int berlin_reset_xlate(struct reset_controller_dev *rcdev, | ||
53 | const struct of_phandle_args *reset_spec) | ||
54 | { | ||
55 | struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev); | ||
56 | unsigned offset, bit; | ||
57 | |||
58 | if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) | ||
59 | return -EINVAL; | ||
60 | |||
61 | offset = reset_spec->args[0]; | ||
62 | bit = reset_spec->args[1]; | ||
63 | |||
64 | if (offset >= priv->size) | ||
65 | return -EINVAL; | ||
66 | |||
67 | if (bit >= BERLIN_MAX_RESETS) | ||
68 | return -EINVAL; | ||
69 | |||
70 | return (offset << 8) | bit; | ||
71 | } | ||
72 | |||
73 | static int __berlin_reset_init(struct device_node *np) | ||
74 | { | ||
75 | struct berlin_reset_priv *priv; | ||
76 | struct resource res; | ||
77 | resource_size_t size; | ||
78 | int ret; | ||
79 | |||
80 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
81 | if (!priv) | ||
82 | return -ENOMEM; | ||
83 | |||
84 | ret = of_address_to_resource(np, 0, &res); | ||
85 | if (ret) | ||
86 | goto err; | ||
87 | |||
88 | size = resource_size(&res); | ||
89 | priv->base = ioremap(res.start, size); | ||
90 | if (!priv->base) { | ||
91 | ret = -ENOMEM; | ||
92 | goto err; | ||
93 | } | ||
94 | priv->size = size; | ||
95 | |||
96 | priv->rcdev.owner = THIS_MODULE; | ||
97 | priv->rcdev.ops = &berlin_reset_ops; | ||
98 | priv->rcdev.of_node = np; | ||
99 | priv->rcdev.of_reset_n_cells = 2; | ||
100 | priv->rcdev.of_xlate = berlin_reset_xlate; | ||
101 | |||
102 | reset_controller_register(&priv->rcdev); | ||
103 | |||
104 | return 0; | ||
105 | |||
106 | err: | ||
107 | kfree(priv); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static const struct of_device_id berlin_reset_of_match[] __initconst = { | ||
112 | { .compatible = "marvell,berlin2-chip-ctrl" }, | ||
113 | { .compatible = "marvell,berlin2cd-chip-ctrl" }, | ||
114 | { .compatible = "marvell,berlin2q-chip-ctrl" }, | ||
115 | { }, | ||
116 | }; | ||
117 | |||
118 | static int __init berlin_reset_init(void) | ||
119 | { | ||
120 | struct device_node *np; | ||
121 | int ret; | ||
122 | |||
123 | for_each_matching_node(np, berlin_reset_of_match) { | ||
124 | ret = __berlin_reset_init(np); | ||
125 | if (ret) | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | arch_initcall(berlin_reset_init); | ||