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 * __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 *clk = NULL; 97 struct clk_init_data init; 98 99 if (!parent_name || id > SYSTEM_MAX_ID) 100 return ERR_PTR(-EINVAL); 101 102 sys = kzalloc(sizeof(*sys), GFP_KERNEL); 103 if (!sys) 104 return ERR_PTR(-ENOMEM); 105 106 init.name = name; 107 init.ops = &system_ops; 108 init.parent_names = &parent_name; 109 init.num_parents = 1; 110 init.flags = CLK_SET_RATE_PARENT; 111 112 sys->id = id; 113 sys->hw.init = &init; 114 sys->regmap = regmap; 115 116 clk = clk_register(NULL, &sys->hw); 117 if (IS_ERR(clk)) 118 kfree(sys); 119 120 return clk; 121 } 122 123 static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) 124 { 125 int num; 126 u32 id; 127 struct clk *clk; 128 const char *name; 129 struct device_node *sysclknp; 130 const char *parent_name; 131 struct regmap *regmap; 132 133 num = of_get_child_count(np); 134 if (num > (SYSTEM_MAX_ID + 1)) 135 return; 136 137 regmap = syscon_node_to_regmap(of_get_parent(np)); 138 if (IS_ERR(regmap)) 139 return; 140 141 for_each_child_of_node(np, sysclknp) { 142 if (of_property_read_u32(sysclknp, "reg", &id)) 143 continue; 144 145 if (of_property_read_string(np, "clock-output-names", &name)) 146 name = sysclknp->name; 147 148 parent_name = of_clk_get_parent_name(sysclknp, 0); 149 150 clk = at91_clk_register_system(regmap, name, parent_name, id); 151 if (IS_ERR(clk)) 152 continue; 153 154 of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk); 155 } 156 } 157 CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", 158 of_at91rm9200_clk_sys_setup); 159