diff options
author | Masahiro Yamada <yamada.masahiro@socionext.com> | 2016-09-16 03:40:03 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-09-16 19:31:33 -0400 |
commit | 734d82f4a678e897a3197b3e61313e32c9e77f46 (patch) | |
tree | 6e9d2b530454ef455d720aad98543924ca036215 | |
parent | bd8dd593f7d2211f2273e05741d157b0c8d020ae (diff) |
clk: uniphier: add core support code for UniPhier clock driver
This includes UniPhier clock driver code, except SoC-specific
data arrays.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/clk/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/uniphier/Kconfig | 9 | ||||
-rw-r--r-- | drivers/clk/uniphier/Makefile | 5 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier-core.c | 123 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier-fixed-factor.c | 48 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier-fixed-rate.c | 47 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier-gate.c | 97 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier-mux.c | 95 | ||||
-rw-r--r-- | drivers/clk/uniphier/clk-uniphier.h | 109 |
11 files changed, 536 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index d695e65cb168..42ec61c5eaa6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1828,6 +1828,7 @@ F: arch/arm/mach-uniphier/ | |||
1828 | F: arch/arm/mm/cache-uniphier.c | 1828 | F: arch/arm/mm/cache-uniphier.c |
1829 | F: arch/arm64/boot/dts/socionext/ | 1829 | F: arch/arm64/boot/dts/socionext/ |
1830 | F: drivers/bus/uniphier-system-bus.c | 1830 | F: drivers/bus/uniphier-system-bus.c |
1831 | F: drivers/clk/uniphier/ | ||
1831 | F: drivers/i2c/busses/i2c-uniphier* | 1832 | F: drivers/i2c/busses/i2c-uniphier* |
1832 | F: drivers/pinctrl/uniphier/ | 1833 | F: drivers/pinctrl/uniphier/ |
1833 | F: drivers/tty/serial/8250/8250_uniphier.c | 1834 | F: drivers/tty/serial/8250/8250_uniphier.c |
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index bf7d540d6965..6a8ac04bedeb 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -209,5 +209,6 @@ source "drivers/clk/samsung/Kconfig" | |||
209 | source "drivers/clk/sunxi-ng/Kconfig" | 209 | source "drivers/clk/sunxi-ng/Kconfig" |
210 | source "drivers/clk/tegra/Kconfig" | 210 | source "drivers/clk/tegra/Kconfig" |
211 | source "drivers/clk/ti/Kconfig" | 211 | source "drivers/clk/ti/Kconfig" |
212 | source "drivers/clk/uniphier/Kconfig" | ||
212 | 213 | ||
213 | endmenu | 214 | endmenu |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e775a836247c..8264d81af5a9 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -84,6 +84,7 @@ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ | |||
84 | obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ | 84 | obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ |
85 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | 85 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ |
86 | obj-y += ti/ | 86 | obj-y += ti/ |
87 | obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ | ||
87 | obj-$(CONFIG_ARCH_U8500) += ux500/ | 88 | obj-$(CONFIG_ARCH_U8500) += ux500/ |
88 | obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ | 89 | obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ |
89 | obj-$(CONFIG_X86) += x86/ | 90 | obj-$(CONFIG_X86) += x86/ |
diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig new file mode 100644 index 000000000000..5512377bd62b --- /dev/null +++ b/drivers/clk/uniphier/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config CLK_UNIPHIER | ||
2 | bool "Clock driver for UniPhier SoCs" | ||
3 | depends on ARCH_UNIPHIER || COMPILE_TEST | ||
4 | depends on OF && MFD_SYSCON | ||
5 | default ARCH_UNIPHIER | ||
6 | help | ||
7 | Support for clock controllers on UniPhier SoCs. | ||
8 | Say Y if you want to control clocks provided by System Control | ||
9 | block, Media I/O block, Peripheral Block. | ||
diff --git a/drivers/clk/uniphier/Makefile b/drivers/clk/uniphier/Makefile new file mode 100644 index 000000000000..88a28cad86b1 --- /dev/null +++ b/drivers/clk/uniphier/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-y += clk-uniphier-core.o | ||
2 | obj-y += clk-uniphier-fixed-factor.o | ||
3 | obj-y += clk-uniphier-fixed-rate.o | ||
4 | obj-y += clk-uniphier-gate.o | ||
5 | obj-y += clk-uniphier-mux.o | ||
diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c new file mode 100644 index 000000000000..a6e2a9404c7d --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-core.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Socionext Inc. | ||
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
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/clk-provider.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mfd/syscon.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include "clk-uniphier.h" | ||
24 | |||
25 | static struct clk_hw *uniphier_clk_register(struct device *dev, | ||
26 | struct regmap *regmap, | ||
27 | const struct uniphier_clk_data *data) | ||
28 | { | ||
29 | switch (data->type) { | ||
30 | case UNIPHIER_CLK_TYPE_FIXED_FACTOR: | ||
31 | return uniphier_clk_register_fixed_factor(dev, data->name, | ||
32 | &data->data.factor); | ||
33 | case UNIPHIER_CLK_TYPE_FIXED_RATE: | ||
34 | return uniphier_clk_register_fixed_rate(dev, data->name, | ||
35 | &data->data.rate); | ||
36 | case UNIPHIER_CLK_TYPE_GATE: | ||
37 | return uniphier_clk_register_gate(dev, regmap, data->name, | ||
38 | &data->data.gate); | ||
39 | case UNIPHIER_CLK_TYPE_MUX: | ||
40 | return uniphier_clk_register_mux(dev, regmap, data->name, | ||
41 | &data->data.mux); | ||
42 | default: | ||
43 | dev_err(dev, "unsupported clock type\n"); | ||
44 | return ERR_PTR(-EINVAL); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | static int uniphier_clk_probe(struct platform_device *pdev) | ||
49 | { | ||
50 | struct device *dev = &pdev->dev; | ||
51 | struct clk_hw_onecell_data *hw_data; | ||
52 | const struct uniphier_clk_data *p, *data; | ||
53 | struct regmap *regmap; | ||
54 | struct device_node *parent; | ||
55 | int clk_num = 0; | ||
56 | |||
57 | data = of_device_get_match_data(dev); | ||
58 | if (WARN_ON(!data)) | ||
59 | return -EINVAL; | ||
60 | |||
61 | parent = of_get_parent(dev->of_node); /* parent should be syscon node */ | ||
62 | regmap = syscon_node_to_regmap(parent); | ||
63 | of_node_put(parent); | ||
64 | if (IS_ERR(regmap)) { | ||
65 | dev_err(dev, "failed to get regmap (error %ld)\n", | ||
66 | PTR_ERR(regmap)); | ||
67 | return PTR_ERR(regmap); | ||
68 | } | ||
69 | |||
70 | for (p = data; p->name; p++) | ||
71 | clk_num = max(clk_num, p->idx + 1); | ||
72 | |||
73 | hw_data = devm_kzalloc(dev, | ||
74 | sizeof(*hw_data) + clk_num * sizeof(struct clk_hw *), | ||
75 | GFP_KERNEL); | ||
76 | if (!hw_data) | ||
77 | return -ENOMEM; | ||
78 | |||
79 | hw_data->num = clk_num; | ||
80 | |||
81 | /* avoid returning NULL for unused idx */ | ||
82 | for (; clk_num >= 0; clk_num--) | ||
83 | hw_data->hws[clk_num] = ERR_PTR(-EINVAL); | ||
84 | |||
85 | for (p = data; p->name; p++) { | ||
86 | struct clk_hw *hw; | ||
87 | |||
88 | dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx); | ||
89 | hw = uniphier_clk_register(dev, regmap, p); | ||
90 | if (IS_ERR(hw)) { | ||
91 | dev_err(dev, "failed to register %s (error %ld)\n", | ||
92 | p->name, PTR_ERR(hw)); | ||
93 | return PTR_ERR(hw); | ||
94 | } | ||
95 | |||
96 | if (p->idx >= 0) | ||
97 | hw_data->hws[p->idx] = hw; | ||
98 | } | ||
99 | |||
100 | return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | ||
101 | hw_data); | ||
102 | } | ||
103 | |||
104 | static int uniphier_clk_remove(struct platform_device *pdev) | ||
105 | { | ||
106 | of_clk_del_provider(pdev->dev.of_node); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static const struct of_device_id uniphier_clk_match[] = { | ||
112 | { /* sentinel */ } | ||
113 | }; | ||
114 | |||
115 | static struct platform_driver uniphier_clk_driver = { | ||
116 | .probe = uniphier_clk_probe, | ||
117 | .remove = uniphier_clk_remove, | ||
118 | .driver = { | ||
119 | .name = "uniphier-clk", | ||
120 | .of_match_table = uniphier_clk_match, | ||
121 | }, | ||
122 | }; | ||
123 | builtin_platform_driver(uniphier_clk_driver); | ||
diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-factor.c b/drivers/clk/uniphier/clk-uniphier-fixed-factor.c new file mode 100644 index 000000000000..da2d9f47ef9f --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-fixed-factor.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Socionext Inc. | ||
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
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/clk-provider.h> | ||
17 | #include <linux/device.h> | ||
18 | |||
19 | #include "clk-uniphier.h" | ||
20 | |||
21 | struct clk_hw *uniphier_clk_register_fixed_factor(struct device *dev, | ||
22 | const char *name, | ||
23 | const struct uniphier_clk_fixed_factor_data *data) | ||
24 | { | ||
25 | struct clk_fixed_factor *fix; | ||
26 | struct clk_init_data init; | ||
27 | int ret; | ||
28 | |||
29 | fix = devm_kzalloc(dev, sizeof(*fix), GFP_KERNEL); | ||
30 | if (!fix) | ||
31 | return ERR_PTR(-ENOMEM); | ||
32 | |||
33 | init.name = name; | ||
34 | init.ops = &clk_fixed_factor_ops; | ||
35 | init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; | ||
36 | init.parent_names = data->parent_name ? &data->parent_name : NULL; | ||
37 | init.num_parents = data->parent_name ? 1 : 0; | ||
38 | |||
39 | fix->mult = data->mult; | ||
40 | fix->div = data->div; | ||
41 | fix->hw.init = &init; | ||
42 | |||
43 | ret = devm_clk_hw_register(dev, &fix->hw); | ||
44 | if (ret) | ||
45 | return ERR_PTR(ret); | ||
46 | |||
47 | return &fix->hw; | ||
48 | } | ||
diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c new file mode 100644 index 000000000000..0ad0d46173c0 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Socionext Inc. | ||
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
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/clk-provider.h> | ||
17 | #include <linux/device.h> | ||
18 | |||
19 | #include "clk-uniphier.h" | ||
20 | |||
21 | struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, | ||
22 | const char *name, | ||
23 | const struct uniphier_clk_fixed_rate_data *data) | ||
24 | { | ||
25 | struct clk_fixed_rate *fixed; | ||
26 | struct clk_init_data init; | ||
27 | int ret; | ||
28 | |||
29 | /* allocate fixed-rate clock */ | ||
30 | fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL); | ||
31 | if (!fixed) | ||
32 | return ERR_PTR(-ENOMEM); | ||
33 | |||
34 | init.name = name; | ||
35 | init.ops = &clk_fixed_rate_ops; | ||
36 | init.parent_names = NULL; | ||
37 | init.num_parents = 0; | ||
38 | |||
39 | fixed->fixed_rate = data->fixed_rate; | ||
40 | fixed->hw.init = &init; | ||
41 | |||
42 | ret = devm_clk_hw_register(dev, &fixed->hw); | ||
43 | if (ret) | ||
44 | return ERR_PTR(ret); | ||
45 | |||
46 | return &fixed->hw; | ||
47 | } | ||
diff --git a/drivers/clk/uniphier/clk-uniphier-gate.c b/drivers/clk/uniphier/clk-uniphier-gate.c new file mode 100644 index 000000000000..49142d44446d --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-gate.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Socionext Inc. | ||
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
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/clk-provider.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/regmap.h> | ||
19 | |||
20 | #include "clk-uniphier.h" | ||
21 | |||
22 | struct uniphier_clk_gate { | ||
23 | struct clk_hw hw; | ||
24 | struct regmap *regmap; | ||
25 | unsigned int reg; | ||
26 | unsigned int bit; | ||
27 | }; | ||
28 | |||
29 | #define to_uniphier_clk_gate(_hw) \ | ||
30 | container_of(_hw, struct uniphier_clk_gate, hw) | ||
31 | |||
32 | static int uniphier_clk_gate_endisable(struct clk_hw *hw, int enable) | ||
33 | { | ||
34 | struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); | ||
35 | |||
36 | return regmap_write_bits(gate->regmap, gate->reg, BIT(gate->bit), | ||
37 | enable ? BIT(gate->bit) : 0); | ||
38 | } | ||
39 | |||
40 | static int uniphier_clk_gate_enable(struct clk_hw *hw) | ||
41 | { | ||
42 | return uniphier_clk_gate_endisable(hw, 1); | ||
43 | } | ||
44 | |||
45 | static void uniphier_clk_gate_disable(struct clk_hw *hw) | ||
46 | { | ||
47 | if (uniphier_clk_gate_endisable(hw, 0) < 0) | ||
48 | pr_warn("failed to disable clk\n"); | ||
49 | } | ||
50 | |||
51 | static int uniphier_clk_gate_is_enabled(struct clk_hw *hw) | ||
52 | { | ||
53 | struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); | ||
54 | unsigned int val; | ||
55 | |||
56 | if (regmap_read(gate->regmap, gate->reg, &val) < 0) | ||
57 | pr_warn("is_enabled() may return wrong result\n"); | ||
58 | |||
59 | return !!(val & BIT(gate->bit)); | ||
60 | } | ||
61 | |||
62 | static const struct clk_ops uniphier_clk_gate_ops = { | ||
63 | .enable = uniphier_clk_gate_enable, | ||
64 | .disable = uniphier_clk_gate_disable, | ||
65 | .is_enabled = uniphier_clk_gate_is_enabled, | ||
66 | }; | ||
67 | |||
68 | struct clk_hw *uniphier_clk_register_gate(struct device *dev, | ||
69 | struct regmap *regmap, | ||
70 | const char *name, | ||
71 | const struct uniphier_clk_gate_data *data) | ||
72 | { | ||
73 | struct uniphier_clk_gate *gate; | ||
74 | struct clk_init_data init; | ||
75 | int ret; | ||
76 | |||
77 | gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); | ||
78 | if (!gate) | ||
79 | return ERR_PTR(-ENOMEM); | ||
80 | |||
81 | init.name = name; | ||
82 | init.ops = &uniphier_clk_gate_ops; | ||
83 | init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; | ||
84 | init.parent_names = data->parent_name ? &data->parent_name : NULL; | ||
85 | init.num_parents = data->parent_name ? 1 : 0; | ||
86 | |||
87 | gate->regmap = regmap; | ||
88 | gate->reg = data->reg; | ||
89 | gate->bit = data->bit; | ||
90 | gate->hw.init = &init; | ||
91 | |||
92 | ret = devm_clk_hw_register(dev, &gate->hw); | ||
93 | if (ret) | ||
94 | return ERR_PTR(ret); | ||
95 | |||
96 | return &gate->hw; | ||
97 | } | ||
diff --git a/drivers/clk/uniphier/clk-uniphier-mux.c b/drivers/clk/uniphier/clk-uniphier-mux.c new file mode 100644 index 000000000000..15a2f2cbe0d9 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-mux.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Socionext Inc. | ||
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
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/clk-provider.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/regmap.h> | ||
19 | |||
20 | #include "clk-uniphier.h" | ||
21 | |||
22 | struct uniphier_clk_mux { | ||
23 | struct clk_hw hw; | ||
24 | struct regmap *regmap; | ||
25 | unsigned int reg; | ||
26 | const unsigned int *masks; | ||
27 | const unsigned int *vals; | ||
28 | }; | ||
29 | |||
30 | #define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw) | ||
31 | |||
32 | static int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index) | ||
33 | { | ||
34 | struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); | ||
35 | |||
36 | return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index], | ||
37 | mux->vals[index]); | ||
38 | } | ||
39 | |||
40 | static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw) | ||
41 | { | ||
42 | struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); | ||
43 | int num_parents = clk_hw_get_num_parents(hw); | ||
44 | int ret; | ||
45 | u32 val; | ||
46 | u8 i; | ||
47 | |||
48 | ret = regmap_read(mux->regmap, mux->reg, &val); | ||
49 | if (ret) | ||
50 | return ret; | ||
51 | |||
52 | for (i = 0; i < num_parents; i++) | ||
53 | if ((mux->masks[i] & val) == mux->vals[i]) | ||
54 | return i; | ||
55 | |||
56 | return -EINVAL; | ||
57 | } | ||
58 | |||
59 | static const struct clk_ops uniphier_clk_mux_ops = { | ||
60 | .determine_rate = __clk_mux_determine_rate, | ||
61 | .set_parent = uniphier_clk_mux_set_parent, | ||
62 | .get_parent = uniphier_clk_mux_get_parent, | ||
63 | }; | ||
64 | |||
65 | struct clk_hw *uniphier_clk_register_mux(struct device *dev, | ||
66 | struct regmap *regmap, | ||
67 | const char *name, | ||
68 | const struct uniphier_clk_mux_data *data) | ||
69 | { | ||
70 | struct uniphier_clk_mux *mux; | ||
71 | struct clk_init_data init; | ||
72 | int ret; | ||
73 | |||
74 | mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); | ||
75 | if (!mux) | ||
76 | return ERR_PTR(-ENOMEM); | ||
77 | |||
78 | init.name = name; | ||
79 | init.ops = &uniphier_clk_mux_ops; | ||
80 | init.flags = CLK_SET_RATE_PARENT; | ||
81 | init.parent_names = data->parent_names; | ||
82 | init.num_parents = data->num_parents, | ||
83 | |||
84 | mux->regmap = regmap; | ||
85 | mux->reg = data->reg; | ||
86 | mux->masks = data->masks; | ||
87 | mux->vals = data->vals; | ||
88 | mux->hw.init = &init; | ||
89 | |||
90 | ret = devm_clk_hw_register(dev, &mux->hw); | ||
91 | if (ret) | ||
92 | return ERR_PTR(ret); | ||
93 | |||
94 | return &mux->hw; | ||
95 | } | ||
diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h new file mode 100644 index 000000000000..3e354e907f4e --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 Socionext Inc. | ||
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
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 | #ifndef __CLK_UNIPHIER_H__ | ||
17 | #define __CLK_UNIPHIER_H__ | ||
18 | |||
19 | struct clk_hw; | ||
20 | struct device; | ||
21 | struct regmap; | ||
22 | |||
23 | #define UNIPHIER_CLK_MUX_MAX_PARENTS 8 | ||
24 | |||
25 | enum uniphier_clk_type { | ||
26 | UNIPHIER_CLK_TYPE_FIXED_FACTOR, | ||
27 | UNIPHIER_CLK_TYPE_FIXED_RATE, | ||
28 | UNIPHIER_CLK_TYPE_GATE, | ||
29 | UNIPHIER_CLK_TYPE_MUX, | ||
30 | }; | ||
31 | |||
32 | struct uniphier_clk_fixed_factor_data { | ||
33 | const char *parent_name; | ||
34 | unsigned int mult; | ||
35 | unsigned int div; | ||
36 | }; | ||
37 | |||
38 | struct uniphier_clk_fixed_rate_data { | ||
39 | unsigned long fixed_rate; | ||
40 | }; | ||
41 | |||
42 | struct uniphier_clk_gate_data { | ||
43 | const char *parent_name; | ||
44 | unsigned int reg; | ||
45 | unsigned int bit; | ||
46 | }; | ||
47 | |||
48 | struct uniphier_clk_mux_data { | ||
49 | const char *parent_names[UNIPHIER_CLK_MUX_MAX_PARENTS]; | ||
50 | unsigned int num_parents; | ||
51 | unsigned int reg; | ||
52 | unsigned int masks[UNIPHIER_CLK_MUX_MAX_PARENTS]; | ||
53 | unsigned int vals[UNIPHIER_CLK_MUX_MAX_PARENTS]; | ||
54 | }; | ||
55 | |||
56 | struct uniphier_clk_data { | ||
57 | const char *name; | ||
58 | enum uniphier_clk_type type; | ||
59 | int idx; | ||
60 | union { | ||
61 | struct uniphier_clk_fixed_factor_data factor; | ||
62 | struct uniphier_clk_fixed_rate_data rate; | ||
63 | struct uniphier_clk_gate_data gate; | ||
64 | struct uniphier_clk_mux_data mux; | ||
65 | } data; | ||
66 | }; | ||
67 | |||
68 | #define UNIPHIER_CLK_FACTOR(_name, _idx, _parent, _mult, _div) \ | ||
69 | { \ | ||
70 | .name = (_name), \ | ||
71 | .type = UNIPHIER_CLK_TYPE_FIXED_FACTOR, \ | ||
72 | .idx = (_idx), \ | ||
73 | .data.factor = { \ | ||
74 | .parent_name = (_parent), \ | ||
75 | .mult = (_mult), \ | ||
76 | .div = (_div), \ | ||
77 | }, \ | ||
78 | } | ||
79 | |||
80 | |||
81 | #define UNIPHIER_CLK_GATE(_name, _idx, _parent, _reg, _bit) \ | ||
82 | { \ | ||
83 | .name = (_name), \ | ||
84 | .type = UNIPHIER_CLK_TYPE_GATE, \ | ||
85 | .idx = (_idx), \ | ||
86 | .data.gate = { \ | ||
87 | .parent_name = (_parent), \ | ||
88 | .reg = (_reg), \ | ||
89 | .bit = (_bit), \ | ||
90 | }, \ | ||
91 | } | ||
92 | |||
93 | |||
94 | struct clk_hw *uniphier_clk_register_fixed_factor(struct device *dev, | ||
95 | const char *name, | ||
96 | const struct uniphier_clk_fixed_factor_data *data); | ||
97 | struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, | ||
98 | const char *name, | ||
99 | const struct uniphier_clk_fixed_rate_data *data); | ||
100 | struct clk_hw *uniphier_clk_register_gate(struct device *dev, | ||
101 | struct regmap *regmap, | ||
102 | const char *name, | ||
103 | const struct uniphier_clk_gate_data *data); | ||
104 | struct clk_hw *uniphier_clk_register_mux(struct device *dev, | ||
105 | struct regmap *regmap, | ||
106 | const char *name, | ||
107 | const struct uniphier_clk_mux_data *data); | ||
108 | |||
109 | #endif /* __CLK_UNIPHIER_H__ */ | ||