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 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 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