Merge tag 'sound-3.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[cascardo/linux.git] / drivers / clk / clk-s2mps11.c
1 /*
2  * clk-s2mps11.c - Clock driver for S2MPS11.
3  *
4  * Copyright (C) 2013,2014 Samsung Electornics
5  *
6  * This program is free software; you can redistribute  it and/or modify it
7  * under  the terms of  the GNU General  Public License as published by the
8  * Free Software Foundation;  either version 2 of the  License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <linux/module.h>
19 #include <linux/err.h>
20 #include <linux/of.h>
21 #include <linux/clkdev.h>
22 #include <linux/regmap.h>
23 #include <linux/clk-provider.h>
24 #include <linux/platform_device.h>
25 #include <linux/mfd/samsung/s2mps11.h>
26 #include <linux/mfd/samsung/s2mps14.h>
27 #include <linux/mfd/samsung/s5m8767.h>
28 #include <linux/mfd/samsung/core.h>
29
30 #define s2mps11_name(a) (a->hw.init->name)
31
32 static struct clk **clk_table;
33 static struct clk_onecell_data clk_data;
34
35 enum {
36         S2MPS11_CLK_AP = 0,
37         S2MPS11_CLK_CP,
38         S2MPS11_CLK_BT,
39         S2MPS11_CLKS_NUM,
40 };
41
42 struct s2mps11_clk {
43         struct sec_pmic_dev *iodev;
44         struct device_node *clk_np;
45         struct clk_hw hw;
46         struct clk *clk;
47         struct clk_lookup *lookup;
48         u32 mask;
49         unsigned int reg;
50 };
51
52 static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
53 {
54         return container_of(hw, struct s2mps11_clk, hw);
55 }
56
57 static int s2mps11_clk_prepare(struct clk_hw *hw)
58 {
59         struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
60         int ret;
61
62         ret = regmap_update_bits(s2mps11->iodev->regmap_pmic,
63                                  s2mps11->reg,
64                                  s2mps11->mask, s2mps11->mask);
65
66         return ret;
67 }
68
69 static void s2mps11_clk_unprepare(struct clk_hw *hw)
70 {
71         struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
72         int ret;
73
74         ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
75                            s2mps11->mask, ~s2mps11->mask);
76 }
77
78 static int s2mps11_clk_is_prepared(struct clk_hw *hw)
79 {
80         int ret;
81         u32 val;
82         struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
83
84         ret = regmap_read(s2mps11->iodev->regmap_pmic,
85                                 s2mps11->reg, &val);
86         if (ret < 0)
87                 return -EINVAL;
88
89         return val & s2mps11->mask;
90 }
91
92 static unsigned long s2mps11_clk_recalc_rate(struct clk_hw *hw,
93                                              unsigned long parent_rate)
94 {
95         return 32768;
96 }
97
98 static struct clk_ops s2mps11_clk_ops = {
99         .prepare        = s2mps11_clk_prepare,
100         .unprepare      = s2mps11_clk_unprepare,
101         .is_prepared    = s2mps11_clk_is_prepared,
102         .recalc_rate    = s2mps11_clk_recalc_rate,
103 };
104
105 static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
106         [S2MPS11_CLK_AP] = {
107                 .name = "s2mps11_ap",
108                 .ops = &s2mps11_clk_ops,
109                 .flags = CLK_IS_ROOT,
110         },
111         [S2MPS11_CLK_CP] = {
112                 .name = "s2mps11_cp",
113                 .ops = &s2mps11_clk_ops,
114                 .flags = CLK_IS_ROOT,
115         },
116         [S2MPS11_CLK_BT] = {
117                 .name = "s2mps11_bt",
118                 .ops = &s2mps11_clk_ops,
119                 .flags = CLK_IS_ROOT,
120         },
121 };
122
123 static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = {
124         [S2MPS11_CLK_AP] = {
125                 .name = "s2mps14_ap",
126                 .ops = &s2mps11_clk_ops,
127                 .flags = CLK_IS_ROOT,
128         },
129         [S2MPS11_CLK_BT] = {
130                 .name = "s2mps14_bt",
131                 .ops = &s2mps11_clk_ops,
132                 .flags = CLK_IS_ROOT,
133         },
134 };
135
136 static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev,
137                 struct clk_init_data *clks_init)
138 {
139         struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
140         struct device_node *clk_np;
141         int i;
142
143         if (!iodev->dev->of_node)
144                 return ERR_PTR(-EINVAL);
145
146         clk_np = of_get_child_by_name(iodev->dev->of_node, "clocks");
147         if (!clk_np) {
148                 dev_err(&pdev->dev, "could not find clock sub-node\n");
149                 return ERR_PTR(-EINVAL);
150         }
151
152         for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
153                 if (!clks_init[i].name)
154                         continue; /* Skip clocks not present in some devices */
155                 of_property_read_string_index(clk_np, "clock-output-names", i,
156                                 &clks_init[i].name);
157         }
158
159         return clk_np;
160 }
161
162 static int s2mps11_clk_probe(struct platform_device *pdev)
163 {
164         struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
165         struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
166         unsigned int s2mps11_reg;
167         struct clk_init_data *clks_init;
168         int i, ret = 0;
169
170         s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) *
171                                         S2MPS11_CLKS_NUM, GFP_KERNEL);
172         if (!s2mps11_clks)
173                 return -ENOMEM;
174
175         s2mps11_clk = s2mps11_clks;
176
177         clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
178                                  S2MPS11_CLKS_NUM, GFP_KERNEL);
179         if (!clk_table)
180                 return -ENOMEM;
181
182         switch(platform_get_device_id(pdev)->driver_data) {
183         case S2MPS11X:
184                 s2mps11_reg = S2MPS11_REG_RTC_CTRL;
185                 clks_init = s2mps11_clks_init;
186                 break;
187         case S2MPS14X:
188                 s2mps11_reg = S2MPS14_REG_RTCCTRL;
189                 clks_init = s2mps14_clks_init;
190                 break;
191         case S5M8767X:
192                 s2mps11_reg = S5M8767_REG_CTRL1;
193                 clks_init = s2mps11_clks_init;
194                 break;
195         default:
196                 dev_err(&pdev->dev, "Invalid device type\n");
197                 return -EINVAL;
198         };
199
200         /* Store clocks of_node in first element of s2mps11_clks array */
201         s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, clks_init);
202         if (IS_ERR(s2mps11_clks->clk_np))
203                 return PTR_ERR(s2mps11_clks->clk_np);
204
205         for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
206                 if (!clks_init[i].name)
207                         continue; /* Skip clocks not present in some devices */
208                 s2mps11_clk->iodev = iodev;
209                 s2mps11_clk->hw.init = &clks_init[i];
210                 s2mps11_clk->mask = 1 << i;
211                 s2mps11_clk->reg = s2mps11_reg;
212
213                 s2mps11_clk->clk = devm_clk_register(&pdev->dev,
214                                                         &s2mps11_clk->hw);
215                 if (IS_ERR(s2mps11_clk->clk)) {
216                         dev_err(&pdev->dev, "Fail to register : %s\n",
217                                                 s2mps11_name(s2mps11_clk));
218                         ret = PTR_ERR(s2mps11_clk->clk);
219                         goto err_reg;
220                 }
221
222                 s2mps11_clk->lookup = clkdev_alloc(s2mps11_clk->clk,
223                                         s2mps11_name(s2mps11_clk), NULL);
224                 if (!s2mps11_clk->lookup) {
225                         ret = -ENOMEM;
226                         goto err_lup;
227                 }
228
229                 clkdev_add(s2mps11_clk->lookup);
230         }
231
232         for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
233                 /* Skip clocks not present on S2MPS14 */
234                 if (!clks_init[i].name)
235                         continue;
236                 clk_table[i] = s2mps11_clks[i].clk;
237         }
238
239         clk_data.clks = clk_table;
240         clk_data.clk_num = S2MPS11_CLKS_NUM;
241         of_clk_add_provider(s2mps11_clks->clk_np, of_clk_src_onecell_get,
242                         &clk_data);
243
244         platform_set_drvdata(pdev, s2mps11_clks);
245
246         return ret;
247 err_lup:
248         devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
249 err_reg:
250         while (s2mps11_clk > s2mps11_clks) {
251                 if (s2mps11_clk->lookup) {
252                         clkdev_drop(s2mps11_clk->lookup);
253                         devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
254                 }
255                 s2mps11_clk--;
256         }
257
258         return ret;
259 }
260
261 static int s2mps11_clk_remove(struct platform_device *pdev)
262 {
263         struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev);
264         int i;
265
266         of_clk_del_provider(s2mps11_clks[0].clk_np);
267         /* Drop the reference obtained in s2mps11_clk_parse_dt */
268         of_node_put(s2mps11_clks[0].clk_np);
269
270         for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
271                 /* Skip clocks not present on S2MPS14 */
272                 if (!s2mps11_clks[i].lookup)
273                         continue;
274                 clkdev_drop(s2mps11_clks[i].lookup);
275         }
276
277         return 0;
278 }
279
280 static const struct platform_device_id s2mps11_clk_id[] = {
281         { "s2mps11-clk", S2MPS11X},
282         { "s2mps14-clk", S2MPS14X},
283         { "s5m8767-clk", S5M8767X},
284         { },
285 };
286 MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
287
288 static struct platform_driver s2mps11_clk_driver = {
289         .driver = {
290                 .name  = "s2mps11-clk",
291                 .owner = THIS_MODULE,
292         },
293         .probe = s2mps11_clk_probe,
294         .remove = s2mps11_clk_remove,
295         .id_table = s2mps11_clk_id,
296 };
297
298 static int __init s2mps11_clk_init(void)
299 {
300         return platform_driver_register(&s2mps11_clk_driver);
301 }
302 subsys_initcall(s2mps11_clk_init);
303
304 static void __init s2mps11_clk_cleanup(void)
305 {
306         platform_driver_unregister(&s2mps11_clk_driver);
307 }
308 module_exit(s2mps11_clk_cleanup);
309
310 MODULE_DESCRIPTION("S2MPS11 Clock Driver");
311 MODULE_AUTHOR("Yadwinder Singh Brar <yadi.brar@samsung.com>");
312 MODULE_LICENSE("GPL");