1 /* 2 * drivers/clk/at91/clk-slow.c 3 * 4 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 */ 12 13 #include <linux/clk-provider.h> 14 #include <linux/clkdev.h> 15 #include <linux/clk/at91_pmc.h> 16 #include <linux/of.h> 17 #include <linux/mfd/syscon.h> 18 #include <linux/regmap.h> 19 20 #include "pmc.h" 21 22 struct clk_sam9260_slow { 23 struct clk_hw hw; 24 struct regmap *regmap; 25 }; 26 27 #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw) 28 29 static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) 30 { 31 struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw); 32 unsigned int status; 33 34 regmap_read(slowck->regmap, AT91_PMC_SR, &status); 35 36 return status & AT91_PMC_OSCSEL ? 1 : 0; 37 } 38 39 static const struct clk_ops sam9260_slow_ops = { 40 .get_parent = clk_sam9260_slow_get_parent, 41 }; 42 43 static struct clk_hw * __init 44 at91_clk_register_sam9260_slow(struct regmap *regmap, 45 const char *name, 46 const char **parent_names, 47 int num_parents) 48 { 49 struct clk_sam9260_slow *slowck; 50 struct clk_hw *hw; 51 struct clk_init_data init; 52 int ret; 53 54 if (!name) 55 return ERR_PTR(-EINVAL); 56 57 if (!parent_names || !num_parents) 58 return ERR_PTR(-EINVAL); 59 60 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); 61 if (!slowck) 62 return ERR_PTR(-ENOMEM); 63 64 init.name = name; 65 init.ops = &sam9260_slow_ops; 66 init.parent_names = parent_names; 67 init.num_parents = num_parents; 68 init.flags = 0; 69 70 slowck->hw.init = &init; 71 slowck->regmap = regmap; 72 73 hw = &slowck->hw; 74 ret = clk_hw_register(NULL, &slowck->hw); 75 if (ret) { 76 kfree(slowck); 77 hw = ERR_PTR(ret); 78 } 79 80 return hw; 81 } 82 83 static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) 84 { 85 struct clk_hw *hw; 86 const char *parent_names[2]; 87 unsigned int num_parents; 88 const char *name = np->name; 89 struct regmap *regmap; 90 91 num_parents = of_clk_get_parent_count(np); 92 if (num_parents != 2) 93 return; 94 95 of_clk_parent_fill(np, parent_names, num_parents); 96 regmap = syscon_node_to_regmap(of_get_parent(np)); 97 if (IS_ERR(regmap)) 98 return; 99 100 of_property_read_string(np, "clock-output-names", &name); 101 102 hw = at91_clk_register_sam9260_slow(regmap, name, parent_names, 103 num_parents); 104 if (IS_ERR(hw)) 105 return; 106 107 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); 108 } 109 110 CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", 111 of_at91sam9260_clk_slow_setup); 112