1 /* 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License version 2 as 4 * published by the Free Software Foundation. 5 * 6 * This program is distributed in the hope that it will be useful, 7 * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 * GNU General Public License for more details. 10 * 11 * Copyright (C) 2013 ARM Limited 12 */ 13 14 #include <linux/amba/sp810.h> 15 #include <linux/clkdev.h> 16 #include <linux/clk-provider.h> 17 #include <linux/err.h> 18 #include <linux/of.h> 19 #include <linux/of_address.h> 20 21 #define to_clk_sp810_timerclken(_hw) \ 22 container_of(_hw, struct clk_sp810_timerclken, hw) 23 24 struct clk_sp810; 25 26 struct clk_sp810_timerclken { 27 struct clk_hw hw; 28 struct clk *clk; 29 struct clk_sp810 *sp810; 30 int channel; 31 }; 32 33 struct clk_sp810 { 34 struct device_node *node; 35 int refclk_index, timclk_index; 36 void __iomem *base; 37 spinlock_t lock; 38 struct clk_sp810_timerclken timerclken[4]; 39 struct clk *refclk; 40 struct clk *timclk; 41 }; 42 43 static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw) 44 { 45 struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); 46 u32 val = readl(timerclken->sp810->base + SCCTRL); 47 48 return !!(val & (1 << SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel))); 49 } 50 51 static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index) 52 { 53 struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); 54 struct clk_sp810 *sp810 = timerclken->sp810; 55 u32 val, shift = SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel); 56 unsigned long flags = 0; 57 58 if (WARN_ON(index > 1)) 59 return -EINVAL; 60 61 spin_lock_irqsave(&sp810->lock, flags); 62 63 val = readl(sp810->base + SCCTRL); 64 val &= ~(1 << shift); 65 val |= index << shift; 66 writel(val, sp810->base + SCCTRL); 67 68 spin_unlock_irqrestore(&sp810->lock, flags); 69 70 return 0; 71 } 72 73 /* 74 * FIXME - setting the parent every time .prepare is invoked is inefficient. 75 * This is better handled by a dedicated clock tree configuration mechanism at 76 * init-time. Revisit this later when such a mechanism exists 77 */ 78 static int clk_sp810_timerclken_prepare(struct clk_hw *hw) 79 { 80 struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); 81 struct clk_sp810 *sp810 = timerclken->sp810; 82 struct clk *old_parent = __clk_get_parent(hw->clk); 83 struct clk *new_parent; 84 85 if (!sp810->refclk) 86 sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index); 87 88 if (!sp810->timclk) 89 sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index); 90 91 if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk))) 92 return -ENOENT; 93 94 /* Select fastest parent */ 95 if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk)) 96 new_parent = sp810->refclk; 97 else 98 new_parent = sp810->timclk; 99 100 /* Switch the parent if necessary */ 101 if (old_parent != new_parent) { 102 clk_prepare(new_parent); 103 clk_set_parent(hw->clk, new_parent); 104 clk_unprepare(old_parent); 105 } 106 107 return 0; 108 } 109 110 static void clk_sp810_timerclken_unprepare(struct clk_hw *hw) 111 { 112 struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); 113 struct clk_sp810 *sp810 = timerclken->sp810; 114 115 clk_put(sp810->timclk); 116 clk_put(sp810->refclk); 117 } 118 119 static const struct clk_ops clk_sp810_timerclken_ops = { 120 .prepare = clk_sp810_timerclken_prepare, 121 .unprepare = clk_sp810_timerclken_unprepare, 122 .get_parent = clk_sp810_timerclken_get_parent, 123 .set_parent = clk_sp810_timerclken_set_parent, 124 }; 125 126 struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec, 127 void *data) 128 { 129 struct clk_sp810 *sp810 = data; 130 131 if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] > 132 ARRAY_SIZE(sp810->timerclken))) 133 return NULL; 134 135 return sp810->timerclken[clkspec->args[0]].clk; 136 } 137 138 void __init clk_sp810_of_setup(struct device_node *node) 139 { 140 struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL); 141 const char *parent_names[2]; 142 char name[12]; 143 struct clk_init_data init; 144 int i; 145 146 if (!sp810) { 147 pr_err("Failed to allocate memory for SP810!\n"); 148 return; 149 } 150 151 sp810->refclk_index = of_property_match_string(node, "clock-names", 152 "refclk"); 153 parent_names[0] = of_clk_get_parent_name(node, sp810->refclk_index); 154 155 sp810->timclk_index = of_property_match_string(node, "clock-names", 156 "timclk"); 157 parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index); 158 159 if (parent_names[0] <= 0 || parent_names[1] <= 0) { 160 pr_warn("Failed to obtain parent clocks for SP810!\n"); 161 return; 162 } 163 164 sp810->node = node; 165 sp810->base = of_iomap(node, 0); 166 spin_lock_init(&sp810->lock); 167 168 init.name = name; 169 init.ops = &clk_sp810_timerclken_ops; 170 init.flags = CLK_IS_BASIC; 171 init.parent_names = parent_names; 172 init.num_parents = ARRAY_SIZE(parent_names); 173 174 for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { 175 snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); 176 177 sp810->timerclken[i].sp810 = sp810; 178 sp810->timerclken[i].channel = i; 179 sp810->timerclken[i].hw.init = &init; 180 181 sp810->timerclken[i].clk = clk_register(NULL, 182 &sp810->timerclken[i].hw); 183 WARN_ON(IS_ERR(sp810->timerclken[i].clk)); 184 } 185 186 of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810); 187 } 188 CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup); 189