Skip to content

Commit 734d82f

Browse files
masahir0ybebarino
authored andcommitted
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 <[email protected]> Signed-off-by: Stephen Boyd <[email protected]>
1 parent bd8dd59 commit 734d82f

File tree

11 files changed

+536
-0
lines changed

11 files changed

+536
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,6 +1828,7 @@ F: arch/arm/mach-uniphier/
18281828
F: arch/arm/mm/cache-uniphier.c
18291829
F: arch/arm64/boot/dts/socionext/
18301830
F: drivers/bus/uniphier-system-bus.c
1831+
F: drivers/clk/uniphier/
18311832
F: drivers/i2c/busses/i2c-uniphier*
18321833
F: drivers/pinctrl/uniphier/
18331834
F: drivers/tty/serial/8250/8250_uniphier.c

drivers/clk/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,6 @@ source "drivers/clk/samsung/Kconfig"
209209
source "drivers/clk/sunxi-ng/Kconfig"
210210
source "drivers/clk/tegra/Kconfig"
211211
source "drivers/clk/ti/Kconfig"
212+
source "drivers/clk/uniphier/Kconfig"
212213

213214
endmenu

drivers/clk/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ obj-$(CONFIG_ARCH_SUNXI) += sunxi/
8484
obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
8585
obj-$(CONFIG_ARCH_TEGRA) += tegra/
8686
obj-y += ti/
87+
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
8788
obj-$(CONFIG_ARCH_U8500) += ux500/
8889
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
8990
obj-$(CONFIG_X86) += x86/

drivers/clk/uniphier/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

drivers/clk/uniphier/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright (C) 2016 Socionext Inc.
3+
* Author: Masahiro Yamada <[email protected]>
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);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2016 Socionext Inc.
3+
* Author: Masahiro Yamada <[email protected]>
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+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (C) 2016 Socionext Inc.
3+
* Author: Masahiro Yamada <[email protected]>
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+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (C) 2016 Socionext Inc.
3+
* Author: Masahiro Yamada <[email protected]>
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+
}

0 commit comments

Comments
 (0)