diff options
author | Codrin Ciubotariu <codrin.ciubotariu@microchip.com> | 2018-06-18 10:12:36 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2018-07-06 14:12:20 -0400 |
commit | 96e4ea8c253d12079db4d7174990455b4bbf0c87 (patch) | |
tree | a0cb6049dad098bcad9e8a11fcdc763be3482a90 | |
parent | 5f273c0d9facfea124f6dea9de41775085056cc2 (diff) |
clk: at91: add I2S clock mux driver
This driver is a simple muxing driver that controls the
I2S's clock input by using syscon/regmap to change the parent.
The available inputs can be peripheral clock and generated clock.
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
[sboyd@kernel.org: Fix SPDX tag comment style]
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r-- | arch/arm/mach-at91/Kconfig | 4 | ||||
-rw-r--r-- | drivers/clk/at91/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/at91/clk-i2s-mux.c | 116 |
3 files changed, 121 insertions, 0 deletions
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 1254bf9d91b4..903f23c309df 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig | |||
@@ -27,6 +27,7 @@ config SOC_SAMA5D2 | |||
27 | select HAVE_AT91_H32MX | 27 | select HAVE_AT91_H32MX |
28 | select HAVE_AT91_GENERATED_CLK | 28 | select HAVE_AT91_GENERATED_CLK |
29 | select HAVE_AT91_AUDIO_PLL | 29 | select HAVE_AT91_AUDIO_PLL |
30 | select HAVE_AT91_I2S_MUX_CLK | ||
30 | select PINCTRL_AT91PIO4 | 31 | select PINCTRL_AT91PIO4 |
31 | help | 32 | help |
32 | Select this if ou are using one of Microchip's SAMA5D2 family SoC. | 33 | Select this if ou are using one of Microchip's SAMA5D2 family SoC. |
@@ -129,6 +130,9 @@ config HAVE_AT91_GENERATED_CLK | |||
129 | config HAVE_AT91_AUDIO_PLL | 130 | config HAVE_AT91_AUDIO_PLL |
130 | bool | 131 | bool |
131 | 132 | ||
133 | config HAVE_AT91_I2S_MUX_CLK | ||
134 | bool | ||
135 | |||
132 | config SOC_SAM_V4_V5 | 136 | config SOC_SAM_V4_V5 |
133 | bool | 137 | bool |
134 | 138 | ||
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 082596f37c1d..facc169ebb68 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile | |||
@@ -13,3 +13,4 @@ obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o | |||
13 | obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o | 13 | obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o |
14 | obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o | 14 | obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o |
15 | obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o | 15 | obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o |
16 | obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o | ||
diff --git a/drivers/clk/at91/clk-i2s-mux.c b/drivers/clk/at91/clk-i2s-mux.c new file mode 100644 index 000000000000..f0c3c3079f04 --- /dev/null +++ b/drivers/clk/at91/clk-i2s-mux.c | |||
@@ -0,0 +1,116 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 2018 Microchip Technology Inc, | ||
4 | * Codrin Ciubotariu <codrin.ciubotariu@microchip.com> | ||
5 | * | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk-provider.h> | ||
10 | #include <linux/of.h> | ||
11 | #include <linux/mfd/syscon.h> | ||
12 | #include <linux/regmap.h> | ||
13 | #include <linux/slab.h> | ||
14 | |||
15 | #include <soc/at91/atmel-sfr.h> | ||
16 | |||
17 | #define I2S_BUS_NR 2 | ||
18 | |||
19 | struct clk_i2s_mux { | ||
20 | struct clk_hw hw; | ||
21 | struct regmap *regmap; | ||
22 | u8 bus_id; | ||
23 | }; | ||
24 | |||
25 | #define to_clk_i2s_mux(hw) container_of(hw, struct clk_i2s_mux, hw) | ||
26 | |||
27 | static u8 clk_i2s_mux_get_parent(struct clk_hw *hw) | ||
28 | { | ||
29 | struct clk_i2s_mux *mux = to_clk_i2s_mux(hw); | ||
30 | u32 val; | ||
31 | |||
32 | regmap_read(mux->regmap, AT91_SFR_I2SCLKSEL, &val); | ||
33 | |||
34 | return (val & BIT(mux->bus_id)) >> mux->bus_id; | ||
35 | } | ||
36 | |||
37 | static int clk_i2s_mux_set_parent(struct clk_hw *hw, u8 index) | ||
38 | { | ||
39 | struct clk_i2s_mux *mux = to_clk_i2s_mux(hw); | ||
40 | |||
41 | return regmap_update_bits(mux->regmap, AT91_SFR_I2SCLKSEL, | ||
42 | BIT(mux->bus_id), index << mux->bus_id); | ||
43 | } | ||
44 | |||
45 | static const struct clk_ops clk_i2s_mux_ops = { | ||
46 | .get_parent = clk_i2s_mux_get_parent, | ||
47 | .set_parent = clk_i2s_mux_set_parent, | ||
48 | .determine_rate = __clk_mux_determine_rate, | ||
49 | }; | ||
50 | |||
51 | static struct clk_hw * __init | ||
52 | at91_clk_i2s_mux_register(struct regmap *regmap, const char *name, | ||
53 | const char * const *parent_names, | ||
54 | unsigned int num_parents, u8 bus_id) | ||
55 | { | ||
56 | struct clk_init_data init = {}; | ||
57 | struct clk_i2s_mux *i2s_ck; | ||
58 | int ret; | ||
59 | |||
60 | i2s_ck = kzalloc(sizeof(*i2s_ck), GFP_KERNEL); | ||
61 | if (!i2s_ck) | ||
62 | return ERR_PTR(-ENOMEM); | ||
63 | |||
64 | init.name = name; | ||
65 | init.ops = &clk_i2s_mux_ops; | ||
66 | init.parent_names = parent_names; | ||
67 | init.num_parents = num_parents; | ||
68 | |||
69 | i2s_ck->hw.init = &init; | ||
70 | i2s_ck->bus_id = bus_id; | ||
71 | i2s_ck->regmap = regmap; | ||
72 | |||
73 | ret = clk_hw_register(NULL, &i2s_ck->hw); | ||
74 | if (ret) { | ||
75 | kfree(i2s_ck); | ||
76 | return ERR_PTR(ret); | ||
77 | } | ||
78 | |||
79 | return &i2s_ck->hw; | ||
80 | } | ||
81 | |||
82 | static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) | ||
83 | { | ||
84 | struct regmap *regmap_sfr; | ||
85 | u8 bus_id; | ||
86 | const char *parent_names[2]; | ||
87 | struct device_node *i2s_mux_np; | ||
88 | struct clk_hw *hw; | ||
89 | int ret; | ||
90 | |||
91 | regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); | ||
92 | if (IS_ERR(regmap_sfr)) | ||
93 | return; | ||
94 | |||
95 | for_each_child_of_node(np, i2s_mux_np) { | ||
96 | if (of_property_read_u8(i2s_mux_np, "reg", &bus_id)) | ||
97 | continue; | ||
98 | |||
99 | if (bus_id > I2S_BUS_NR) | ||
100 | continue; | ||
101 | |||
102 | ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); | ||
103 | if (ret != 2) | ||
104 | continue; | ||
105 | |||
106 | hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, | ||
107 | parent_names, 2, bus_id); | ||
108 | if (IS_ERR(hw)) | ||
109 | continue; | ||
110 | |||
111 | of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux", | ||
116 | of_sama5d2_clk_i2s_mux_setup); | ||