1 /* 2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 */ 10 11 #include <linux/clk-provider.h> 12 #include <linux/clkdev.h> 13 #include <linux/clk/at91_pmc.h> 14 #include <linux/of.h> 15 #include <linux/mfd/syscon.h> 16 #include <linux/regmap.h> 17 18 #include "pmc.h" 19 20 #define SYSTEM_MAX_ID 31 21 22 #define SYSTEM_MAX_NAME_SZ 32 23 24 #define to_clk_system(hw) container_of(hw, struct clk_system, hw) 25 struct clk_system { 26 struct clk_hw hw; 27 struct regmap *regmap; 28 u8 id; 29 }; 30 31 static inline int is_pck(int id) 32 { 33 return (id >= 8) && (id <= 15); 34 } 35 36 static inline bool clk_system_ready(struct regmap *regmap, int id) 37 { 38 unsigned int status; 39 40 regmap_read(regmap, AT91_PMC_SR, &status); 41 42 return status & (1 << id) ? 1 : 0; 43 } 44 45 static int clk_system_prepare(struct clk_hw *hw) 46 { 47 struct clk_system *sys = to_clk_system(hw); 48 49 regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id); 50 51 if (!is_pck(sys->id)) 52 return 0; 53 54 while (!clk_system_ready(sys->regmap, sys->id)) 55 cpu_relax(); 56 57 return 0; 58 } 59 60 static void clk_system_unprepare(struct clk_hw *hw) 61 { 62 struct clk_system *sys = to_clk_system(hw); 63 64 regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id); 65 } 66 67 static int clk_system_is_prepared(struct clk_hw *hw) 68 { 69 struct clk_system *sys = to_clk_system(hw); 70 unsigned int status; 71 72 regmap_read(sys->regmap, AT91_PMC_SCSR, &status); 73 74 if (!(status & (1 << sys->id))) 75 return 0; 76 77 if (!is_pck(sys->id)) 78 return 1; 79 80 regmap_read(sys->regmap, AT91_PMC_SR, &status); 81 82 return status & (1 << sys->id) ? 1 : 0; 83 } 84 85 static const struct clk_ops system_ops = { 86 .prepare = clk_system_prepare, 87 .unprepare = clk_system_unprepare, 88 .is_prepared = clk_system_is_prepared, 89 }; 90 91 static struct clk_hw * __init 92 at91_clk_register_system(struct regmap *regmap, const char *name, 93 const char *parent_name, u8 id) 94 { 95 struct clk_system *sys; 96 struct clk_hw *hw; 97 struct clk_init_data init; 98 int ret; 99 100 if (!parent_name || id > SYSTEM_MAX_ID) 101 return ERR_PTR(-EINVAL); 102 103 sys = kzalloc(sizeof(*sys), GFP_KERNEL); 104 if (!sys) 105 return ERR_PTR(-ENOMEM); 106 107 init.name = name; 108 init.ops = &system_ops; 109 init.parent_names = &parent_name; 110 init.num_parents = 1; 111 init.flags = CLK_SET_RATE_PARENT; 112 113 sys->id = id; 114 sys->hw.init = &init; 115 sys->regmap = regmap; 116 117 hw = &sys->hw; 118 ret = clk_hw_register(NULL, &sys->hw); 119 if (ret) { 120 kfree(sys); 121 hw = ERR_PTR(ret); 122 } 123 124 return hw; 125 } 126 127 static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) 128 { 129 int num; 130 u32 id; 131 struct clk_hw *hw; 132 const char *name; 133 struct device_node *sysclknp; 134 const char *parent_name; 135 struct regmap *regmap; 136 137 num = of_get_child_count(np); 138 if (num > (SYSTEM_MAX_ID + 1)) 139 return; 140 141 regmap = syscon_node_to_regmap(of_get_parent(np)); 142 if (IS_ERR(regmap)) 143 return; 144 145 for_each_child_of_node(np, sysclknp) { 146 if (of_property_read_u32(sysclknp, "reg", &id)) 147 continue; 148 149 if (of_property_read_string(np, "clock-output-names", &name)) 150 name = sysclknp->name; 151 152 parent_name = of_clk_get_parent_name(sysclknp, 0); 153 154 hw = at91_clk_register_system(regmap, name, parent_name, id); 155 if (IS_ERR(hw)) 156 continue; 157 158 of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw); 159 } 160 } 161 CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", 162 of_at91rm9200_clk_sys_setup); 163