Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux...
[cascardo/linux.git] / drivers / clk / nxp / clk-lpc18xx-creg.c
1 /*
2  * Clk driver for NXP LPC18xx/43xx Configuration Registers (CREG)
3  *
4  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2. This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10
11 #include <linux/clk-provider.h>
12 #include <linux/delay.h>
13 #include <linux/kernel.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18
19 #define LPC18XX_CREG_CREG0                      0x004
20 #define  LPC18XX_CREG_CREG0_EN1KHZ              BIT(0)
21 #define  LPC18XX_CREG_CREG0_EN32KHZ             BIT(1)
22 #define  LPC18XX_CREG_CREG0_RESET32KHZ          BIT(2)
23 #define  LPC18XX_CREG_CREG0_PD32KHZ             BIT(3)
24
25 #define to_clk_creg(_hw) container_of(_hw, struct clk_creg_data, hw)
26
27 enum {
28         CREG_CLK_1KHZ,
29         CREG_CLK_32KHZ,
30         CREG_CLK_MAX,
31 };
32
33 struct clk_creg_data {
34         struct clk_hw hw;
35         const char *name;
36         struct regmap *reg;
37         unsigned int en_mask;
38         const struct clk_ops *ops;
39 };
40
41 #define CREG_CLK(_name, _emask, _ops)           \
42 {                                               \
43         .name = _name,                          \
44         .en_mask = LPC18XX_CREG_CREG0_##_emask, \
45         .ops = &_ops,                           \
46 }
47
48 static int clk_creg_32k_prepare(struct clk_hw *hw)
49 {
50         struct clk_creg_data *creg = to_clk_creg(hw);
51         int ret;
52
53         ret = regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
54                                  LPC18XX_CREG_CREG0_PD32KHZ |
55                                  LPC18XX_CREG_CREG0_RESET32KHZ, 0);
56
57         /*
58          * Powering up the 32k oscillator takes a long while
59          * and sadly there aren't any status bit to poll.
60          */
61         msleep(2500);
62
63         return ret;
64 }
65
66 static void clk_creg_32k_unprepare(struct clk_hw *hw)
67 {
68         struct clk_creg_data *creg = to_clk_creg(hw);
69
70         regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
71                            LPC18XX_CREG_CREG0_PD32KHZ,
72                            LPC18XX_CREG_CREG0_PD32KHZ);
73 }
74
75 static int clk_creg_32k_is_prepared(struct clk_hw *hw)
76 {
77         struct clk_creg_data *creg = to_clk_creg(hw);
78         u32 reg;
79
80         regmap_read(creg->reg, LPC18XX_CREG_CREG0, &reg);
81
82         return !(reg & LPC18XX_CREG_CREG0_PD32KHZ) &&
83                !(reg & LPC18XX_CREG_CREG0_RESET32KHZ);
84 }
85
86 static unsigned long clk_creg_1k_recalc_rate(struct clk_hw *hw,
87                                              unsigned long parent_rate)
88 {
89         return parent_rate / 32;
90 }
91
92 static int clk_creg_enable(struct clk_hw *hw)
93 {
94         struct clk_creg_data *creg = to_clk_creg(hw);
95
96         return regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
97                                   creg->en_mask, creg->en_mask);
98 }
99
100 static void clk_creg_disable(struct clk_hw *hw)
101 {
102         struct clk_creg_data *creg = to_clk_creg(hw);
103
104         regmap_update_bits(creg->reg, LPC18XX_CREG_CREG0,
105                            creg->en_mask, 0);
106 }
107
108 static int clk_creg_is_enabled(struct clk_hw *hw)
109 {
110         struct clk_creg_data *creg = to_clk_creg(hw);
111         u32 reg;
112
113         regmap_read(creg->reg, LPC18XX_CREG_CREG0, &reg);
114
115         return !!(reg & creg->en_mask);
116 }
117
118 static const struct clk_ops clk_creg_32k = {
119         .enable         = clk_creg_enable,
120         .disable        = clk_creg_disable,
121         .is_enabled     = clk_creg_is_enabled,
122         .prepare        = clk_creg_32k_prepare,
123         .unprepare      = clk_creg_32k_unprepare,
124         .is_prepared    = clk_creg_32k_is_prepared,
125 };
126
127 static const struct clk_ops clk_creg_1k = {
128         .enable         = clk_creg_enable,
129         .disable        = clk_creg_disable,
130         .is_enabled     = clk_creg_is_enabled,
131         .recalc_rate    = clk_creg_1k_recalc_rate,
132 };
133
134 static struct clk_creg_data clk_creg_clocks[] = {
135         [CREG_CLK_1KHZ]  = CREG_CLK("1khz_clk",  EN1KHZ,  clk_creg_1k),
136         [CREG_CLK_32KHZ] = CREG_CLK("32khz_clk", EN32KHZ, clk_creg_32k),
137 };
138
139 static struct clk *clk_register_creg_clk(struct device *dev,
140                                          struct clk_creg_data *creg_clk,
141                                          const char **parent_name,
142                                          struct regmap *syscon)
143 {
144         struct clk_init_data init;
145
146         init.ops = creg_clk->ops;
147         init.name = creg_clk->name;
148         init.parent_names = parent_name;
149         init.num_parents = 1;
150         init.flags = 0;
151
152         creg_clk->reg = syscon;
153         creg_clk->hw.init = &init;
154
155         if (dev)
156                 return devm_clk_register(dev, &creg_clk->hw);
157
158         return clk_register(NULL, &creg_clk->hw);
159 }
160
161 static struct clk *clk_creg_early[CREG_CLK_MAX];
162 static struct clk_onecell_data clk_creg_early_data = {
163         .clks = clk_creg_early,
164         .clk_num = CREG_CLK_MAX,
165 };
166
167 static void __init lpc18xx_creg_clk_init(struct device_node *np)
168 {
169         const char *clk_32khz_parent;
170         struct regmap *syscon;
171
172         syscon = syscon_node_to_regmap(np->parent);
173         if (IS_ERR(syscon)) {
174                 pr_err("%s: syscon lookup failed\n", __func__);
175                 return;
176         }
177
178         clk_32khz_parent = of_clk_get_parent_name(np, 0);
179
180         clk_creg_early[CREG_CLK_32KHZ] =
181                 clk_register_creg_clk(NULL, &clk_creg_clocks[CREG_CLK_32KHZ],
182                                       &clk_32khz_parent, syscon);
183         clk_creg_early[CREG_CLK_1KHZ] = ERR_PTR(-EPROBE_DEFER);
184
185         of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_early_data);
186 }
187 CLK_OF_DECLARE_DRIVER(lpc18xx_creg_clk, "nxp,lpc1850-creg-clk",
188                       lpc18xx_creg_clk_init);
189
190 static struct clk *clk_creg[CREG_CLK_MAX];
191 static struct clk_onecell_data clk_creg_data = {
192         .clks = clk_creg,
193         .clk_num = CREG_CLK_MAX,
194 };
195
196 static int lpc18xx_creg_clk_probe(struct platform_device *pdev)
197 {
198         struct device_node *np = pdev->dev.of_node;
199         struct regmap *syscon;
200
201         syscon = syscon_node_to_regmap(np->parent);
202         if (IS_ERR(syscon)) {
203                 dev_err(&pdev->dev, "syscon lookup failed\n");
204                 return PTR_ERR(syscon);
205         }
206
207         clk_creg[CREG_CLK_32KHZ] = clk_creg_early[CREG_CLK_32KHZ];
208         clk_creg[CREG_CLK_1KHZ] =
209                 clk_register_creg_clk(NULL, &clk_creg_clocks[CREG_CLK_1KHZ],
210                                       &clk_creg_clocks[CREG_CLK_32KHZ].name,
211                                       syscon);
212
213         return of_clk_add_provider(np, of_clk_src_onecell_get, &clk_creg_data);
214 }
215
216 static const struct of_device_id lpc18xx_creg_clk_of_match[] = {
217         { .compatible = "nxp,lpc1850-creg-clk" },
218         {},
219 };
220
221 static struct platform_driver lpc18xx_creg_clk_driver = {
222         .probe = lpc18xx_creg_clk_probe,
223         .driver = {
224                 .name = "lpc18xx-creg-clk",
225                 .of_match_table = lpc18xx_creg_clk_of_match,
226         },
227 };
228 builtin_platform_driver(lpc18xx_creg_clk_driver);