diff options
author | Neil Armstrong <narmstrong@baylibre.com> | 2016-04-18 06:01:35 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-04-21 17:20:07 -0400 |
commit | 0bbd72b4c64fc0803a6efd86ea151184bf553f97 (patch) | |
tree | 62c67da9126fe90eeac31708afe957299f5e2bd1 | |
parent | bb4399b8a5d7d9a8bf9d28b1e78badff1b0e5a5e (diff) |
clk: Add Oxford Semiconductor OXNAS Standard Clocks
Add Oxford Semiconductor OXNAS SoC Family Standard Clocks support.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
[sboyd@codeaurora.org: Drop NULL/continue check in registration
loop]
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | drivers/clk/Kconfig | 6 | ||||
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/clk-oxnas.c | 195 |
3 files changed, 202 insertions, 0 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c45554957499..2dd371deb23b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -197,6 +197,12 @@ config COMMON_CLK_PXA | |||
197 | ---help--- | 197 | ---help--- |
198 | Support for the Marvell PXA SoC. | 198 | Support for the Marvell PXA SoC. |
199 | 199 | ||
200 | config COMMON_CLK_OXNAS | ||
201 | bool "Clock driver for the OXNAS SoC Family" | ||
202 | select MFD_SYSCON | ||
203 | ---help--- | ||
204 | Support for the OXNAS SoC Family clocks. | ||
205 | |||
200 | source "drivers/clk/bcm/Kconfig" | 206 | source "drivers/clk/bcm/Kconfig" |
201 | source "drivers/clk/hisilicon/Kconfig" | 207 | source "drivers/clk/hisilicon/Kconfig" |
202 | source "drivers/clk/mvebu/Kconfig" | 208 | source "drivers/clk/mvebu/Kconfig" |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 54964eb43195..4ef71a13ab37 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -33,6 +33,7 @@ obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o | |||
33 | obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o | 33 | obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o |
34 | obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o | 34 | obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o |
35 | obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o | 35 | obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o |
36 | obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o | ||
36 | obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o | 37 | obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o |
37 | obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o | 38 | obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o |
38 | obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o | 39 | obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o |
diff --git a/drivers/clk/clk-oxnas.c b/drivers/clk/clk-oxnas.c new file mode 100644 index 000000000000..efba7d4dbcfc --- /dev/null +++ b/drivers/clk/clk-oxnas.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Broadcom | ||
3 | * Copyright (C) 2012 Stephen Warren | ||
4 | * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clk-provider.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/stringify.h> | ||
25 | #include <linux/regmap.h> | ||
26 | #include <linux/mfd/syscon.h> | ||
27 | |||
28 | /* Standard regmap gate clocks */ | ||
29 | struct clk_oxnas { | ||
30 | struct clk_hw hw; | ||
31 | signed char bit; | ||
32 | struct regmap *regmap; | ||
33 | }; | ||
34 | |||
35 | /* Regmap offsets */ | ||
36 | #define CLK_STAT_REGOFFSET 0x24 | ||
37 | #define CLK_SET_REGOFFSET 0x2c | ||
38 | #define CLK_CLR_REGOFFSET 0x30 | ||
39 | |||
40 | static inline struct clk_oxnas *to_clk_oxnas(struct clk_hw *hw) | ||
41 | { | ||
42 | return container_of(hw, struct clk_oxnas, hw); | ||
43 | } | ||
44 | |||
45 | static int oxnas_clk_is_enabled(struct clk_hw *hw) | ||
46 | { | ||
47 | struct clk_oxnas *std = to_clk_oxnas(hw); | ||
48 | int ret; | ||
49 | unsigned int val; | ||
50 | |||
51 | ret = regmap_read(std->regmap, CLK_STAT_REGOFFSET, &val); | ||
52 | if (ret < 0) | ||
53 | return ret; | ||
54 | |||
55 | return val & BIT(std->bit); | ||
56 | } | ||
57 | |||
58 | static int oxnas_clk_enable(struct clk_hw *hw) | ||
59 | { | ||
60 | struct clk_oxnas *std = to_clk_oxnas(hw); | ||
61 | |||
62 | regmap_write(std->regmap, CLK_SET_REGOFFSET, BIT(std->bit)); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static void oxnas_clk_disable(struct clk_hw *hw) | ||
68 | { | ||
69 | struct clk_oxnas *std = to_clk_oxnas(hw); | ||
70 | |||
71 | regmap_write(std->regmap, CLK_CLR_REGOFFSET, BIT(std->bit)); | ||
72 | } | ||
73 | |||
74 | static const struct clk_ops oxnas_clk_ops = { | ||
75 | .enable = oxnas_clk_enable, | ||
76 | .disable = oxnas_clk_disable, | ||
77 | .is_enabled = oxnas_clk_is_enabled, | ||
78 | }; | ||
79 | |||
80 | static const char *const oxnas_clk_parents[] = { | ||
81 | "oscillator", | ||
82 | }; | ||
83 | |||
84 | static const char *const eth_parents[] = { | ||
85 | "gmacclk", | ||
86 | }; | ||
87 | |||
88 | #define DECLARE_STD_CLKP(__clk, __parent) \ | ||
89 | static const struct clk_init_data clk_##__clk##_init = { \ | ||
90 | .name = __stringify(__clk), \ | ||
91 | .ops = &oxnas_clk_ops, \ | ||
92 | .parent_names = __parent, \ | ||
93 | .num_parents = ARRAY_SIZE(__parent), \ | ||
94 | } | ||
95 | |||
96 | #define DECLARE_STD_CLK(__clk) DECLARE_STD_CLKP(__clk, oxnas_clk_parents) | ||
97 | |||
98 | /* Hardware Bit - Clock association */ | ||
99 | struct clk_oxnas_init_data { | ||
100 | unsigned long bit; | ||
101 | const struct clk_init_data *clk_init; | ||
102 | }; | ||
103 | |||
104 | /* Clk init data declaration */ | ||
105 | DECLARE_STD_CLK(leon); | ||
106 | DECLARE_STD_CLK(dma_sgdma); | ||
107 | DECLARE_STD_CLK(cipher); | ||
108 | DECLARE_STD_CLK(sata); | ||
109 | DECLARE_STD_CLK(audio); | ||
110 | DECLARE_STD_CLK(usbmph); | ||
111 | DECLARE_STD_CLKP(etha, eth_parents); | ||
112 | DECLARE_STD_CLK(pciea); | ||
113 | DECLARE_STD_CLK(nand); | ||
114 | |||
115 | /* Table index is clock indice */ | ||
116 | static const struct clk_oxnas_init_data clk_oxnas_init[] = { | ||
117 | [0] = {0, &clk_leon_init}, | ||
118 | [1] = {1, &clk_dma_sgdma_init}, | ||
119 | [2] = {2, &clk_cipher_init}, | ||
120 | /* Skip & Do not touch to DDR clock */ | ||
121 | [3] = {4, &clk_sata_init}, | ||
122 | [4] = {5, &clk_audio_init}, | ||
123 | [5] = {6, &clk_usbmph_init}, | ||
124 | [6] = {7, &clk_etha_init}, | ||
125 | [7] = {8, &clk_pciea_init}, | ||
126 | [8] = {9, &clk_nand_init}, | ||
127 | }; | ||
128 | |||
129 | struct clk_oxnas_data { | ||
130 | struct clk_oxnas clk_oxnas[ARRAY_SIZE(clk_oxnas_init)]; | ||
131 | struct clk_onecell_data onecell_data[ARRAY_SIZE(clk_oxnas_init)]; | ||
132 | struct clk *clks[ARRAY_SIZE(clk_oxnas_init)]; | ||
133 | }; | ||
134 | |||
135 | static int oxnas_stdclk_probe(struct platform_device *pdev) | ||
136 | { | ||
137 | struct device_node *np = pdev->dev.of_node; | ||
138 | struct clk_oxnas_data *clk_oxnas; | ||
139 | struct regmap *regmap; | ||
140 | int i; | ||
141 | |||
142 | clk_oxnas = devm_kzalloc(&pdev->dev, sizeof(*clk_oxnas), GFP_KERNEL); | ||
143 | if (!clk_oxnas) | ||
144 | return -ENOMEM; | ||
145 | |||
146 | regmap = syscon_node_to_regmap(of_get_parent(np)); | ||
147 | if (!regmap) { | ||
148 | dev_err(&pdev->dev, "failed to have parent regmap\n"); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | for (i = 0; i < ARRAY_SIZE(clk_oxnas_init); i++) { | ||
153 | struct clk_oxnas *_clk; | ||
154 | |||
155 | _clk = &clk_oxnas->clk_oxnas[i]; | ||
156 | _clk->bit = clk_oxnas_init[i].bit; | ||
157 | _clk->hw.init = clk_oxnas_init[i].clk_init; | ||
158 | _clk->regmap = regmap; | ||
159 | |||
160 | clk_oxnas->clks[i] = | ||
161 | devm_clk_register(&pdev->dev, &_clk->hw); | ||
162 | if (WARN_ON(IS_ERR(clk_oxnas->clks[i]))) | ||
163 | return PTR_ERR(clk_oxnas->clks[i]); | ||
164 | } | ||
165 | |||
166 | clk_oxnas->onecell_data->clks = clk_oxnas->clks; | ||
167 | clk_oxnas->onecell_data->clk_num = ARRAY_SIZE(clk_oxnas_init); | ||
168 | |||
169 | return of_clk_add_provider(np, of_clk_src_onecell_get, | ||
170 | clk_oxnas->onecell_data); | ||
171 | } | ||
172 | |||
173 | static int oxnas_stdclk_remove(struct platform_device *pdev) | ||
174 | { | ||
175 | of_clk_del_provider(pdev->dev.of_node); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static const struct of_device_id oxnas_stdclk_dt_ids[] = { | ||
181 | { .compatible = "oxsemi,ox810se-stdclk" }, | ||
182 | { } | ||
183 | }; | ||
184 | MODULE_DEVICE_TABLE(of, oxnas_stdclk_dt_ids); | ||
185 | |||
186 | static struct platform_driver oxnas_stdclk_driver = { | ||
187 | .probe = oxnas_stdclk_probe, | ||
188 | .remove = oxnas_stdclk_remove, | ||
189 | .driver = { | ||
190 | .name = "oxnas-stdclk", | ||
191 | .of_match_table = oxnas_stdclk_dt_ids, | ||
192 | }, | ||
193 | }; | ||
194 | |||
195 | module_platform_driver(oxnas_stdclk_driver); | ||