Merge branches 'clk-qcom', 'clk-socfpga', 'clk-mediatek', 'clk-lmk' and 'clk-x86...
[linux-2.6-microblaze.git] / drivers / clk / mediatek / clk-mux.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018 MediaTek Inc.
4  * Author: Owen Chen <owen.chen@mediatek.com>
5  */
6
7 #include <linux/of.h>
8 #include <linux/of_address.h>
9 #include <linux/slab.h>
10 #include <linux/mfd/syscon.h>
11
12 #include "clk-mtk.h"
13 #include "clk-mux.h"
14
15 static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
16 {
17         return container_of(hw, struct mtk_clk_mux, hw);
18 }
19
20 static int mtk_clk_mux_enable_setclr(struct clk_hw *hw)
21 {
22         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
23         unsigned long flags = 0;
24
25         if (mux->lock)
26                 spin_lock_irqsave(mux->lock, flags);
27         else
28                 __acquire(mux->lock);
29
30         regmap_write(mux->regmap, mux->data->clr_ofs,
31                      BIT(mux->data->gate_shift));
32
33         /*
34          * If the parent has been changed when the clock was disabled, it will
35          * not be effective yet. Set the update bit to ensure the mux gets
36          * updated.
37          */
38         if (mux->reparent && mux->data->upd_shift >= 0) {
39                 regmap_write(mux->regmap, mux->data->upd_ofs,
40                              BIT(mux->data->upd_shift));
41                 mux->reparent = false;
42         }
43
44         if (mux->lock)
45                 spin_unlock_irqrestore(mux->lock, flags);
46         else
47                 __release(mux->lock);
48
49         return 0;
50 }
51
52 static void mtk_clk_mux_disable_setclr(struct clk_hw *hw)
53 {
54         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
55
56         regmap_write(mux->regmap, mux->data->set_ofs,
57                         BIT(mux->data->gate_shift));
58 }
59
60 static int mtk_clk_mux_is_enabled(struct clk_hw *hw)
61 {
62         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
63         u32 val;
64
65         regmap_read(mux->regmap, mux->data->mux_ofs, &val);
66
67         return (val & BIT(mux->data->gate_shift)) == 0;
68 }
69
70 static u8 mtk_clk_mux_get_parent(struct clk_hw *hw)
71 {
72         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
73         u32 mask = GENMASK(mux->data->mux_width - 1, 0);
74         u32 val;
75
76         regmap_read(mux->regmap, mux->data->mux_ofs, &val);
77         val = (val >> mux->data->mux_shift) & mask;
78
79         return val;
80 }
81
82 static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index)
83 {
84         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
85         u32 mask = GENMASK(mux->data->mux_width - 1, 0);
86         u32 val, orig;
87         unsigned long flags = 0;
88
89         if (mux->lock)
90                 spin_lock_irqsave(mux->lock, flags);
91         else
92                 __acquire(mux->lock);
93
94         regmap_read(mux->regmap, mux->data->mux_ofs, &orig);
95         val = (orig & ~(mask << mux->data->mux_shift))
96                         | (index << mux->data->mux_shift);
97
98         if (val != orig) {
99                 regmap_write(mux->regmap, mux->data->clr_ofs,
100                                 mask << mux->data->mux_shift);
101                 regmap_write(mux->regmap, mux->data->set_ofs,
102                                 index << mux->data->mux_shift);
103
104                 if (mux->data->upd_shift >= 0) {
105                         regmap_write(mux->regmap, mux->data->upd_ofs,
106                                         BIT(mux->data->upd_shift));
107                         mux->reparent = true;
108                 }
109         }
110
111         if (mux->lock)
112                 spin_unlock_irqrestore(mux->lock, flags);
113         else
114                 __release(mux->lock);
115
116         return 0;
117 }
118
119 const struct clk_ops mtk_mux_clr_set_upd_ops = {
120         .get_parent = mtk_clk_mux_get_parent,
121         .set_parent = mtk_clk_mux_set_parent_setclr_lock,
122 };
123
124 const struct clk_ops mtk_mux_gate_clr_set_upd_ops  = {
125         .enable = mtk_clk_mux_enable_setclr,
126         .disable = mtk_clk_mux_disable_setclr,
127         .is_enabled = mtk_clk_mux_is_enabled,
128         .get_parent = mtk_clk_mux_get_parent,
129         .set_parent = mtk_clk_mux_set_parent_setclr_lock,
130 };
131
132 static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
133                                  struct regmap *regmap,
134                                  spinlock_t *lock)
135 {
136         struct mtk_clk_mux *clk_mux;
137         struct clk_init_data init = {};
138         struct clk *clk;
139
140         clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL);
141         if (!clk_mux)
142                 return ERR_PTR(-ENOMEM);
143
144         init.name = mux->name;
145         init.flags = mux->flags | CLK_SET_RATE_PARENT;
146         init.parent_names = mux->parent_names;
147         init.num_parents = mux->num_parents;
148         init.ops = mux->ops;
149
150         clk_mux->regmap = regmap;
151         clk_mux->data = mux;
152         clk_mux->lock = lock;
153         clk_mux->hw.init = &init;
154
155         clk = clk_register(NULL, &clk_mux->hw);
156         if (IS_ERR(clk)) {
157                 kfree(clk_mux);
158                 return clk;
159         }
160
161         return clk;
162 }
163
164 int mtk_clk_register_muxes(const struct mtk_mux *muxes,
165                            int num, struct device_node *node,
166                            spinlock_t *lock,
167                            struct clk_onecell_data *clk_data)
168 {
169         struct regmap *regmap;
170         struct clk *clk;
171         int i;
172
173         regmap = device_node_to_regmap(node);
174         if (IS_ERR(regmap)) {
175                 pr_err("Cannot find regmap for %pOF: %ld\n", node,
176                        PTR_ERR(regmap));
177                 return PTR_ERR(regmap);
178         }
179
180         for (i = 0; i < num; i++) {
181                 const struct mtk_mux *mux = &muxes[i];
182
183                 if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
184                         clk = mtk_clk_register_mux(mux, regmap, lock);
185
186                         if (IS_ERR(clk)) {
187                                 pr_err("Failed to register clk %s: %ld\n",
188                                        mux->name, PTR_ERR(clk));
189                                 continue;
190                         }
191
192                         clk_data->clks[mux->id] = clk;
193                 }
194         }
195
196         return 0;
197 }