xref: /openbmc/linux/drivers/clk/at91/clk-slow.c (revision b2e39dc0bb8107341f6f704472e79fd32d0cef25)
180eded6cSBoris BREZILLON /*
280eded6cSBoris BREZILLON  * drivers/clk/at91/clk-slow.c
380eded6cSBoris BREZILLON  *
480eded6cSBoris BREZILLON  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
580eded6cSBoris BREZILLON  *
680eded6cSBoris BREZILLON  * This program is free software; you can redistribute it and/or modify
780eded6cSBoris BREZILLON  * it under the terms of the GNU General Public License as published by
880eded6cSBoris BREZILLON  * the Free Software Foundation; either version 2 of the License, or
980eded6cSBoris BREZILLON  * (at your option) any later version.
1080eded6cSBoris BREZILLON  *
1180eded6cSBoris BREZILLON  */
1280eded6cSBoris BREZILLON 
1380eded6cSBoris BREZILLON #include <linux/clk-provider.h>
1480eded6cSBoris BREZILLON #include <linux/clkdev.h>
1580eded6cSBoris BREZILLON #include <linux/clk/at91_pmc.h>
1680eded6cSBoris BREZILLON #include <linux/of.h>
171bdf0232SBoris Brezillon #include <linux/mfd/syscon.h>
181bdf0232SBoris Brezillon #include <linux/regmap.h>
1980eded6cSBoris BREZILLON 
2080eded6cSBoris BREZILLON #include "pmc.h"
2180eded6cSBoris BREZILLON 
2280eded6cSBoris BREZILLON struct clk_sam9260_slow {
2380eded6cSBoris BREZILLON 	struct clk_hw hw;
241bdf0232SBoris Brezillon 	struct regmap *regmap;
2580eded6cSBoris BREZILLON };
2680eded6cSBoris BREZILLON 
2780eded6cSBoris BREZILLON #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
2880eded6cSBoris BREZILLON 
2980eded6cSBoris BREZILLON static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
3080eded6cSBoris BREZILLON {
3180eded6cSBoris BREZILLON 	struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
321bdf0232SBoris Brezillon 	unsigned int status;
3380eded6cSBoris BREZILLON 
341bdf0232SBoris Brezillon 	regmap_read(slowck->regmap, AT91_PMC_SR, &status);
351bdf0232SBoris Brezillon 
361bdf0232SBoris Brezillon 	return status & AT91_PMC_OSCSEL ? 1 : 0;
3780eded6cSBoris BREZILLON }
3880eded6cSBoris BREZILLON 
3980eded6cSBoris BREZILLON static const struct clk_ops sam9260_slow_ops = {
4080eded6cSBoris BREZILLON 	.get_parent = clk_sam9260_slow_get_parent,
4180eded6cSBoris BREZILLON };
4280eded6cSBoris BREZILLON 
43*b2e39dc0SAlexandre Belloni struct clk_hw * __init
441bdf0232SBoris Brezillon at91_clk_register_sam9260_slow(struct regmap *regmap,
4580eded6cSBoris BREZILLON 			       const char *name,
4680eded6cSBoris BREZILLON 			       const char **parent_names,
4780eded6cSBoris BREZILLON 			       int num_parents)
4880eded6cSBoris BREZILLON {
4980eded6cSBoris BREZILLON 	struct clk_sam9260_slow *slowck;
50f5644f10SStephen Boyd 	struct clk_hw *hw;
5180eded6cSBoris BREZILLON 	struct clk_init_data init;
52f5644f10SStephen Boyd 	int ret;
5380eded6cSBoris BREZILLON 
541bdf0232SBoris Brezillon 	if (!name)
5580eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
5680eded6cSBoris BREZILLON 
5780eded6cSBoris BREZILLON 	if (!parent_names || !num_parents)
5880eded6cSBoris BREZILLON 		return ERR_PTR(-EINVAL);
5980eded6cSBoris BREZILLON 
6080eded6cSBoris BREZILLON 	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
6180eded6cSBoris BREZILLON 	if (!slowck)
6280eded6cSBoris BREZILLON 		return ERR_PTR(-ENOMEM);
6380eded6cSBoris BREZILLON 
6480eded6cSBoris BREZILLON 	init.name = name;
6580eded6cSBoris BREZILLON 	init.ops = &sam9260_slow_ops;
6680eded6cSBoris BREZILLON 	init.parent_names = parent_names;
6780eded6cSBoris BREZILLON 	init.num_parents = num_parents;
6880eded6cSBoris BREZILLON 	init.flags = 0;
6980eded6cSBoris BREZILLON 
7080eded6cSBoris BREZILLON 	slowck->hw.init = &init;
711bdf0232SBoris Brezillon 	slowck->regmap = regmap;
7280eded6cSBoris BREZILLON 
73f5644f10SStephen Boyd 	hw = &slowck->hw;
74f5644f10SStephen Boyd 	ret = clk_hw_register(NULL, &slowck->hw);
75f5644f10SStephen Boyd 	if (ret) {
7680eded6cSBoris BREZILLON 		kfree(slowck);
77f5644f10SStephen Boyd 		hw = ERR_PTR(ret);
78f5644f10SStephen Boyd 	}
7980eded6cSBoris BREZILLON 
80f5644f10SStephen Boyd 	return hw;
8180eded6cSBoris BREZILLON }
8280eded6cSBoris BREZILLON 
831bdf0232SBoris Brezillon static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
8480eded6cSBoris BREZILLON {
85f5644f10SStephen Boyd 	struct clk_hw *hw;
8680eded6cSBoris BREZILLON 	const char *parent_names[2];
878c1b1e54SStephen Boyd 	unsigned int num_parents;
8880eded6cSBoris BREZILLON 	const char *name = np->name;
891bdf0232SBoris Brezillon 	struct regmap *regmap;
9080eded6cSBoris BREZILLON 
9151a43be9SGeert Uytterhoeven 	num_parents = of_clk_get_parent_count(np);
92e8531ac8SBoris BREZILLON 	if (num_parents != 2)
9380eded6cSBoris BREZILLON 		return;
9480eded6cSBoris BREZILLON 
95f0557fbeSDinh Nguyen 	of_clk_parent_fill(np, parent_names, num_parents);
961bdf0232SBoris Brezillon 	regmap = syscon_node_to_regmap(of_get_parent(np));
971bdf0232SBoris Brezillon 	if (IS_ERR(regmap))
981bdf0232SBoris Brezillon 		return;
9980eded6cSBoris BREZILLON 
10080eded6cSBoris BREZILLON 	of_property_read_string(np, "clock-output-names", &name);
10180eded6cSBoris BREZILLON 
102f5644f10SStephen Boyd 	hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
10380eded6cSBoris BREZILLON 					     num_parents);
104f5644f10SStephen Boyd 	if (IS_ERR(hw))
10580eded6cSBoris BREZILLON 		return;
10680eded6cSBoris BREZILLON 
107f5644f10SStephen Boyd 	of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
10880eded6cSBoris BREZILLON }
1091bdf0232SBoris Brezillon 
1101bdf0232SBoris Brezillon CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
1111bdf0232SBoris Brezillon 	       of_at91sam9260_clk_slow_setup);
112