xref: /openbmc/linux/drivers/clk/clk-s2mps11.c (revision 2c684d89)
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/s2mps13.h>
27 #include <linux/mfd/samsung/s2mps14.h>
28 #include <linux/mfd/samsung/s5m8767.h>
29 #include <linux/mfd/samsung/core.h>
30 
31 #define s2mps11_name(a) (a->hw.init->name)
32 
33 static struct clk **clk_table;
34 static struct clk_onecell_data clk_data;
35 
36 enum {
37 	S2MPS11_CLK_AP = 0,
38 	S2MPS11_CLK_CP,
39 	S2MPS11_CLK_BT,
40 	S2MPS11_CLKS_NUM,
41 };
42 
43 struct s2mps11_clk {
44 	struct sec_pmic_dev *iodev;
45 	struct device_node *clk_np;
46 	struct clk_hw hw;
47 	struct clk *clk;
48 	struct clk_lookup *lookup;
49 	u32 mask;
50 	unsigned int reg;
51 };
52 
53 static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
54 {
55 	return container_of(hw, struct s2mps11_clk, hw);
56 }
57 
58 static int s2mps11_clk_prepare(struct clk_hw *hw)
59 {
60 	struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
61 
62 	return regmap_update_bits(s2mps11->iodev->regmap_pmic,
63 				 s2mps11->reg,
64 				 s2mps11->mask, s2mps11->mask);
65 }
66 
67 static void s2mps11_clk_unprepare(struct clk_hw *hw)
68 {
69 	struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
70 
71 	regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
72 			   s2mps11->mask, ~s2mps11->mask);
73 }
74 
75 static int s2mps11_clk_is_prepared(struct clk_hw *hw)
76 {
77 	int ret;
78 	u32 val;
79 	struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
80 
81 	ret = regmap_read(s2mps11->iodev->regmap_pmic,
82 				s2mps11->reg, &val);
83 	if (ret < 0)
84 		return -EINVAL;
85 
86 	return val & s2mps11->mask;
87 }
88 
89 static unsigned long s2mps11_clk_recalc_rate(struct clk_hw *hw,
90 					     unsigned long parent_rate)
91 {
92 	return 32768;
93 }
94 
95 static struct clk_ops s2mps11_clk_ops = {
96 	.prepare	= s2mps11_clk_prepare,
97 	.unprepare	= s2mps11_clk_unprepare,
98 	.is_prepared	= s2mps11_clk_is_prepared,
99 	.recalc_rate	= s2mps11_clk_recalc_rate,
100 };
101 
102 static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
103 	[S2MPS11_CLK_AP] = {
104 		.name = "s2mps11_ap",
105 		.ops = &s2mps11_clk_ops,
106 		.flags = CLK_IS_ROOT,
107 	},
108 	[S2MPS11_CLK_CP] = {
109 		.name = "s2mps11_cp",
110 		.ops = &s2mps11_clk_ops,
111 		.flags = CLK_IS_ROOT,
112 	},
113 	[S2MPS11_CLK_BT] = {
114 		.name = "s2mps11_bt",
115 		.ops = &s2mps11_clk_ops,
116 		.flags = CLK_IS_ROOT,
117 	},
118 };
119 
120 static struct clk_init_data s2mps13_clks_init[S2MPS11_CLKS_NUM] = {
121 	[S2MPS11_CLK_AP] = {
122 		.name = "s2mps13_ap",
123 		.ops = &s2mps11_clk_ops,
124 		.flags = CLK_IS_ROOT,
125 	},
126 	[S2MPS11_CLK_CP] = {
127 		.name = "s2mps13_cp",
128 		.ops = &s2mps11_clk_ops,
129 		.flags = CLK_IS_ROOT,
130 	},
131 	[S2MPS11_CLK_BT] = {
132 		.name = "s2mps13_bt",
133 		.ops = &s2mps11_clk_ops,
134 		.flags = CLK_IS_ROOT,
135 	},
136 };
137 
138 static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = {
139 	[S2MPS11_CLK_AP] = {
140 		.name = "s2mps14_ap",
141 		.ops = &s2mps11_clk_ops,
142 		.flags = CLK_IS_ROOT,
143 	},
144 	[S2MPS11_CLK_BT] = {
145 		.name = "s2mps14_bt",
146 		.ops = &s2mps11_clk_ops,
147 		.flags = CLK_IS_ROOT,
148 	},
149 };
150 
151 static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev,
152 		struct clk_init_data *clks_init)
153 {
154 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
155 	struct device_node *clk_np;
156 	int i;
157 
158 	if (!iodev->dev->of_node)
159 		return ERR_PTR(-EINVAL);
160 
161 	clk_np = of_get_child_by_name(iodev->dev->of_node, "clocks");
162 	if (!clk_np) {
163 		dev_err(&pdev->dev, "could not find clock sub-node\n");
164 		return ERR_PTR(-EINVAL);
165 	}
166 
167 	for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
168 		if (!clks_init[i].name)
169 			continue; /* Skip clocks not present in some devices */
170 		of_property_read_string_index(clk_np, "clock-output-names", i,
171 				&clks_init[i].name);
172 	}
173 
174 	return clk_np;
175 }
176 
177 static int s2mps11_clk_probe(struct platform_device *pdev)
178 {
179 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
180 	struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
181 	unsigned int s2mps11_reg;
182 	struct clk_init_data *clks_init;
183 	int i, ret = 0;
184 
185 	s2mps11_clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
186 				sizeof(*s2mps11_clk), GFP_KERNEL);
187 	if (!s2mps11_clks)
188 		return -ENOMEM;
189 
190 	s2mps11_clk = s2mps11_clks;
191 
192 	clk_table = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
193 				sizeof(struct clk *), GFP_KERNEL);
194 	if (!clk_table)
195 		return -ENOMEM;
196 
197 	switch(platform_get_device_id(pdev)->driver_data) {
198 	case S2MPS11X:
199 		s2mps11_reg = S2MPS11_REG_RTC_CTRL;
200 		clks_init = s2mps11_clks_init;
201 		break;
202 	case S2MPS13X:
203 		s2mps11_reg = S2MPS13_REG_RTCCTRL;
204 		clks_init = s2mps13_clks_init;
205 		break;
206 	case S2MPS14X:
207 		s2mps11_reg = S2MPS14_REG_RTCCTRL;
208 		clks_init = s2mps14_clks_init;
209 		break;
210 	case S5M8767X:
211 		s2mps11_reg = S5M8767_REG_CTRL1;
212 		clks_init = s2mps11_clks_init;
213 		break;
214 	default:
215 		dev_err(&pdev->dev, "Invalid device type\n");
216 		return -EINVAL;
217 	}
218 
219 	/* Store clocks of_node in first element of s2mps11_clks array */
220 	s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, clks_init);
221 	if (IS_ERR(s2mps11_clks->clk_np))
222 		return PTR_ERR(s2mps11_clks->clk_np);
223 
224 	for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
225 		if (!clks_init[i].name)
226 			continue; /* Skip clocks not present in some devices */
227 		s2mps11_clk->iodev = iodev;
228 		s2mps11_clk->hw.init = &clks_init[i];
229 		s2mps11_clk->mask = 1 << i;
230 		s2mps11_clk->reg = s2mps11_reg;
231 
232 		s2mps11_clk->clk = devm_clk_register(&pdev->dev,
233 							&s2mps11_clk->hw);
234 		if (IS_ERR(s2mps11_clk->clk)) {
235 			dev_err(&pdev->dev, "Fail to register : %s\n",
236 						s2mps11_name(s2mps11_clk));
237 			ret = PTR_ERR(s2mps11_clk->clk);
238 			goto err_reg;
239 		}
240 
241 		s2mps11_clk->lookup = clkdev_create(s2mps11_clk->clk,
242 					s2mps11_name(s2mps11_clk), NULL);
243 		if (!s2mps11_clk->lookup) {
244 			ret = -ENOMEM;
245 			goto err_reg;
246 		}
247 	}
248 
249 	for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
250 		/* Skip clocks not present on S2MPS14 */
251 		if (!clks_init[i].name)
252 			continue;
253 		clk_table[i] = s2mps11_clks[i].clk;
254 	}
255 
256 	clk_data.clks = clk_table;
257 	clk_data.clk_num = S2MPS11_CLKS_NUM;
258 	of_clk_add_provider(s2mps11_clks->clk_np, of_clk_src_onecell_get,
259 			&clk_data);
260 
261 	platform_set_drvdata(pdev, s2mps11_clks);
262 
263 	return ret;
264 
265 err_reg:
266 	while (--i >= 0)
267 		clkdev_drop(s2mps11_clks[i].lookup);
268 
269 	return ret;
270 }
271 
272 static int s2mps11_clk_remove(struct platform_device *pdev)
273 {
274 	struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev);
275 	int i;
276 
277 	of_clk_del_provider(s2mps11_clks[0].clk_np);
278 	/* Drop the reference obtained in s2mps11_clk_parse_dt */
279 	of_node_put(s2mps11_clks[0].clk_np);
280 
281 	for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
282 		/* Skip clocks not present on S2MPS14 */
283 		if (!s2mps11_clks[i].lookup)
284 			continue;
285 		clkdev_drop(s2mps11_clks[i].lookup);
286 	}
287 
288 	return 0;
289 }
290 
291 static const struct platform_device_id s2mps11_clk_id[] = {
292 	{ "s2mps11-clk", S2MPS11X},
293 	{ "s2mps13-clk", S2MPS13X},
294 	{ "s2mps14-clk", S2MPS14X},
295 	{ "s5m8767-clk", S5M8767X},
296 	{ },
297 };
298 MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
299 
300 static struct platform_driver s2mps11_clk_driver = {
301 	.driver = {
302 		.name  = "s2mps11-clk",
303 	},
304 	.probe = s2mps11_clk_probe,
305 	.remove = s2mps11_clk_remove,
306 	.id_table = s2mps11_clk_id,
307 };
308 
309 static int __init s2mps11_clk_init(void)
310 {
311 	return platform_driver_register(&s2mps11_clk_driver);
312 }
313 subsys_initcall(s2mps11_clk_init);
314 
315 static void __exit s2mps11_clk_cleanup(void)
316 {
317 	platform_driver_unregister(&s2mps11_clk_driver);
318 }
319 module_exit(s2mps11_clk_cleanup);
320 
321 MODULE_DESCRIPTION("S2MPS11 Clock Driver");
322 MODULE_AUTHOR("Yadwinder Singh Brar <yadi.brar@samsung.com>");
323 MODULE_LICENSE("GPL");
324