Merge tag 'for-6.2-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-block.git] / drivers / clk / visconti / clkc.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Toshiba Visconti clock controller
4  *
5  * Copyright (c) 2021 TOSHIBA CORPORATION
6  * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
7  *
8  * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
9  */
10
11 #include <linux/clk-provider.h>
12 #include <linux/delay.h>
13 #include <linux/device.h>
14 #include <linux/io.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/regmap.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20
21 #include "clkc.h"
22
23 static inline struct visconti_clk_gate *to_visconti_clk_gate(struct clk_hw *hw)
24 {
25         return container_of(hw, struct visconti_clk_gate, hw);
26 }
27
28 static int visconti_gate_clk_is_enabled(struct clk_hw *hw)
29 {
30         struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
31         u32 clk = BIT(gate->ck_idx);
32         u32 val;
33
34         regmap_read(gate->regmap, gate->ckon_offset, &val);
35         return (val & clk) ? 1 : 0;
36 }
37
38 static void visconti_gate_clk_disable(struct clk_hw *hw)
39 {
40         struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
41         u32 clk = BIT(gate->ck_idx);
42         unsigned long flags;
43
44         spin_lock_irqsave(gate->lock, flags);
45
46         if (!visconti_gate_clk_is_enabled(hw)) {
47                 spin_unlock_irqrestore(gate->lock, flags);
48                 return;
49         }
50
51         regmap_update_bits(gate->regmap, gate->ckoff_offset, clk, clk);
52         spin_unlock_irqrestore(gate->lock, flags);
53 }
54
55 static int visconti_gate_clk_enable(struct clk_hw *hw)
56 {
57         struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
58         u32 clk = BIT(gate->ck_idx);
59         unsigned long flags;
60
61         spin_lock_irqsave(gate->lock, flags);
62         regmap_update_bits(gate->regmap, gate->ckon_offset, clk, clk);
63         spin_unlock_irqrestore(gate->lock, flags);
64
65         return 0;
66 }
67
68 static const struct clk_ops visconti_clk_gate_ops = {
69         .enable = visconti_gate_clk_enable,
70         .disable = visconti_gate_clk_disable,
71         .is_enabled = visconti_gate_clk_is_enabled,
72 };
73
74 static struct clk_hw *visconti_clk_register_gate(struct device *dev,
75                                                  const char *name,
76                                                  const char *parent_name,
77                                                  struct regmap *regmap,
78                                                  const struct visconti_clk_gate_table *clks,
79                                                  u32    rson_offset,
80                                                  u32    rsoff_offset,
81                                                  u8     rs_idx,
82                                                  spinlock_t *lock)
83 {
84         struct visconti_clk_gate *gate;
85         struct clk_parent_data *pdata;
86         struct clk_init_data init;
87         struct clk_hw *hw;
88         int ret;
89
90         pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
91         if (!pdata)
92                 return ERR_PTR(-ENOMEM);
93
94         pdata->name = pdata->fw_name = parent_name;
95
96         gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
97         if (!gate)
98                 return ERR_PTR(-ENOMEM);
99
100         init.name = name;
101         init.ops = &visconti_clk_gate_ops;
102         init.flags = clks->flags;
103         init.parent_data = pdata;
104         init.num_parents = 1;
105
106         gate->regmap = regmap;
107         gate->ckon_offset = clks->ckon_offset;
108         gate->ckoff_offset = clks->ckoff_offset;
109         gate->ck_idx = clks->ck_idx;
110         gate->rson_offset = rson_offset;
111         gate->rsoff_offset = rsoff_offset;
112         gate->rs_idx = rs_idx;
113         gate->lock = lock;
114         gate->hw.init = &init;
115
116         hw = &gate->hw;
117         ret = devm_clk_hw_register(dev, hw);
118         if (ret)
119                 hw = ERR_PTR(ret);
120
121         return hw;
122 }
123
124 int visconti_clk_register_gates(struct visconti_clk_provider *ctx,
125                                 const struct visconti_clk_gate_table *clks,
126                                 int num_gate,
127                                 const struct visconti_reset_data *reset,
128                                 spinlock_t *lock)
129 {
130         struct device *dev = ctx->dev;
131         int i;
132
133         for (i = 0; i < num_gate; i++) {
134                 const char *parent_div_name = clks[i].parent_data[0].name;
135                 struct clk_parent_data *pdata;
136                 u32 rson_offset, rsoff_offset;
137                 struct clk_hw *gate_clk;
138                 struct clk_hw *div_clk;
139                 char *dev_name;
140                 u8 rs_idx;
141
142                 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
143                 if (!pdata)
144                         return -ENOMEM;
145
146                 dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s_div", clks[i].name);
147                 if (!dev_name)
148                         return -ENOMEM;
149
150                 if (clks[i].rs_id != NO_RESET) {
151                         rson_offset = reset[clks[i].rs_id].rson_offset;
152                         rsoff_offset = reset[clks[i].rs_id].rsoff_offset;
153                         rs_idx = reset[clks[i].rs_id].rs_idx;
154                 } else {
155                         rson_offset = rsoff_offset = rs_idx = -1;
156                 }
157
158                 div_clk = devm_clk_hw_register_fixed_factor(dev,
159                                                             dev_name,
160                                                             parent_div_name,
161                                                             0, 1,
162                                                             clks[i].div);
163                 if (IS_ERR(div_clk))
164                         return PTR_ERR(div_clk);
165
166                 gate_clk = visconti_clk_register_gate(dev,
167                                                       clks[i].name,
168                                                       dev_name,
169                                                       ctx->regmap,
170                                                       &clks[i],
171                                                       rson_offset,
172                                                       rsoff_offset,
173                                                       rs_idx,
174                                                       lock);
175                 if (IS_ERR(gate_clk)) {
176                         dev_err(dev, "%s: failed to register clock %s\n",
177                                 __func__, clks[i].name);
178                         return PTR_ERR(gate_clk);
179                 }
180
181                 ctx->clk_data.hws[clks[i].id] = gate_clk;
182         }
183
184         return 0;
185 }
186
187 struct visconti_clk_provider *visconti_init_clk(struct device *dev,
188                                                 struct regmap *regmap,
189                                                 unsigned long nr_clks)
190 {
191         struct visconti_clk_provider *ctx;
192         int i;
193
194         ctx = devm_kzalloc(dev, struct_size(ctx, clk_data.hws, nr_clks), GFP_KERNEL);
195         if (!ctx)
196                 return ERR_PTR(-ENOMEM);
197
198         for (i = 0; i < nr_clks; ++i)
199                 ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
200         ctx->clk_data.num = nr_clks;
201
202         ctx->dev = dev;
203         ctx->regmap = regmap;
204
205         return ctx;
206 }