1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
280eded6cSBoris BREZILLON /*
380eded6cSBoris BREZILLON * drivers/clk/at91/clk-slow.c
480eded6cSBoris BREZILLON *
580eded6cSBoris BREZILLON * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
680eded6cSBoris BREZILLON */
780eded6cSBoris BREZILLON
880eded6cSBoris BREZILLON #include <linux/clk-provider.h>
980eded6cSBoris BREZILLON #include <linux/clkdev.h>
1080eded6cSBoris BREZILLON #include <linux/clk/at91_pmc.h>
1180eded6cSBoris BREZILLON #include <linux/of.h>
121bdf0232SBoris Brezillon #include <linux/mfd/syscon.h>
131bdf0232SBoris Brezillon #include <linux/regmap.h>
1480eded6cSBoris BREZILLON
1580eded6cSBoris BREZILLON #include "pmc.h"
1680eded6cSBoris BREZILLON
1780eded6cSBoris BREZILLON struct clk_sam9260_slow {
1880eded6cSBoris BREZILLON struct clk_hw hw;
191bdf0232SBoris Brezillon struct regmap *regmap;
2080eded6cSBoris BREZILLON };
2180eded6cSBoris BREZILLON
2280eded6cSBoris BREZILLON #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
2380eded6cSBoris BREZILLON
clk_sam9260_slow_get_parent(struct clk_hw * hw)2480eded6cSBoris BREZILLON static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
2580eded6cSBoris BREZILLON {
2680eded6cSBoris BREZILLON struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
271bdf0232SBoris Brezillon unsigned int status;
2880eded6cSBoris BREZILLON
291bdf0232SBoris Brezillon regmap_read(slowck->regmap, AT91_PMC_SR, &status);
301bdf0232SBoris Brezillon
311bdf0232SBoris Brezillon return status & AT91_PMC_OSCSEL ? 1 : 0;
3280eded6cSBoris BREZILLON }
3380eded6cSBoris BREZILLON
3480eded6cSBoris BREZILLON static const struct clk_ops sam9260_slow_ops = {
3580eded6cSBoris BREZILLON .get_parent = clk_sam9260_slow_get_parent,
3680eded6cSBoris BREZILLON };
3780eded6cSBoris BREZILLON
38b2e39dc0SAlexandre Belloni struct clk_hw * __init
at91_clk_register_sam9260_slow(struct regmap * regmap,const char * name,const char ** parent_names,int num_parents)391bdf0232SBoris Brezillon at91_clk_register_sam9260_slow(struct regmap *regmap,
4080eded6cSBoris BREZILLON const char *name,
4180eded6cSBoris BREZILLON const char **parent_names,
4280eded6cSBoris BREZILLON int num_parents)
4380eded6cSBoris BREZILLON {
4480eded6cSBoris BREZILLON struct clk_sam9260_slow *slowck;
45f5644f10SStephen Boyd struct clk_hw *hw;
4680eded6cSBoris BREZILLON struct clk_init_data init;
47f5644f10SStephen Boyd int ret;
4880eded6cSBoris BREZILLON
491bdf0232SBoris Brezillon if (!name)
5080eded6cSBoris BREZILLON return ERR_PTR(-EINVAL);
5180eded6cSBoris BREZILLON
5280eded6cSBoris BREZILLON if (!parent_names || !num_parents)
5380eded6cSBoris BREZILLON return ERR_PTR(-EINVAL);
5480eded6cSBoris BREZILLON
5580eded6cSBoris BREZILLON slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
5680eded6cSBoris BREZILLON if (!slowck)
5780eded6cSBoris BREZILLON return ERR_PTR(-ENOMEM);
5880eded6cSBoris BREZILLON
5980eded6cSBoris BREZILLON init.name = name;
6080eded6cSBoris BREZILLON init.ops = &sam9260_slow_ops;
6180eded6cSBoris BREZILLON init.parent_names = parent_names;
6280eded6cSBoris BREZILLON init.num_parents = num_parents;
6380eded6cSBoris BREZILLON init.flags = 0;
6480eded6cSBoris BREZILLON
6580eded6cSBoris BREZILLON slowck->hw.init = &init;
661bdf0232SBoris Brezillon slowck->regmap = regmap;
6780eded6cSBoris BREZILLON
68f5644f10SStephen Boyd hw = &slowck->hw;
69f5644f10SStephen Boyd ret = clk_hw_register(NULL, &slowck->hw);
70f5644f10SStephen Boyd if (ret) {
7180eded6cSBoris BREZILLON kfree(slowck);
72f5644f10SStephen Boyd hw = ERR_PTR(ret);
73f5644f10SStephen Boyd }
7480eded6cSBoris BREZILLON
75f5644f10SStephen Boyd return hw;
7680eded6cSBoris BREZILLON }
77