Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'mvebu-clk-3.14' of git://git.infradead.org/linux-mvebu into clk-next

mvebu clock changes for v3.14

- mvebu: add the core divider clock driver
- sparse cleanup

+229
+5
drivers/clk/mvebu/Kconfig
··· 4 4 config MVEBU_CLK_CPU 5 5 bool 6 6 7 + config MVEBU_CLK_COREDIV 8 + bool 9 + 7 10 config ARMADA_370_CLK 8 11 bool 9 12 select MVEBU_CLK_COMMON 10 13 select MVEBU_CLK_CPU 14 + select MVEBU_CLK_COREDIV 11 15 12 16 config ARMADA_XP_CLK 13 17 bool 14 18 select MVEBU_CLK_COMMON 15 19 select MVEBU_CLK_CPU 20 + select MVEBU_CLK_COREDIV 16 21 17 22 config DOVE_CLK 18 23 bool
+1
drivers/clk/mvebu/Makefile
··· 1 1 obj-$(CONFIG_MVEBU_CLK_COMMON) += common.o 2 2 obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o 3 + obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o 3 4 4 5 obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o 5 6 obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
+223
drivers/clk/mvebu/clk-corediv.c
··· 1 + /* 2 + * MVEBU Core divider clock 3 + * 4 + * Copyright (C) 2013 Marvell 5 + * 6 + * Ezequiel Garcia <ezequiel.garcia@free-electrons.com> 7 + * 8 + * This file is licensed under the terms of the GNU General Public 9 + * License version 2. This program is licensed "as is" without any 10 + * warranty of any kind, whether express or implied. 11 + */ 12 + 13 + #include <linux/kernel.h> 14 + #include <linux/clk-provider.h> 15 + #include <linux/of_address.h> 16 + #include <linux/slab.h> 17 + #include <linux/delay.h> 18 + #include "common.h" 19 + 20 + #define CORE_CLK_DIV_RATIO_MASK 0xff 21 + #define CORE_CLK_DIV_RATIO_RELOAD BIT(8) 22 + #define CORE_CLK_DIV_ENABLE_OFFSET 24 23 + #define CORE_CLK_DIV_RATIO_OFFSET 0x8 24 + 25 + struct clk_corediv_desc { 26 + unsigned int mask; 27 + unsigned int offset; 28 + unsigned int fieldbit; 29 + }; 30 + 31 + struct clk_corediv { 32 + struct clk_hw hw; 33 + void __iomem *reg; 34 + struct clk_corediv_desc desc; 35 + spinlock_t lock; 36 + }; 37 + 38 + static struct clk_onecell_data clk_data; 39 + 40 + static const struct clk_corediv_desc mvebu_corediv_desc[] __initconst = { 41 + { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ 42 + }; 43 + 44 + #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) 45 + 46 + static int clk_corediv_is_enabled(struct clk_hw *hwclk) 47 + { 48 + struct clk_corediv *corediv = to_corediv_clk(hwclk); 49 + struct clk_corediv_desc *desc = &corediv->desc; 50 + u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET; 51 + 52 + return !!(readl(corediv->reg) & enable_mask); 53 + } 54 + 55 + static int clk_corediv_enable(struct clk_hw *hwclk) 56 + { 57 + struct clk_corediv *corediv = to_corediv_clk(hwclk); 58 + struct clk_corediv_desc *desc = &corediv->desc; 59 + unsigned long flags = 0; 60 + u32 reg; 61 + 62 + spin_lock_irqsave(&corediv->lock, flags); 63 + 64 + reg = readl(corediv->reg); 65 + reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); 66 + writel(reg, corediv->reg); 67 + 68 + spin_unlock_irqrestore(&corediv->lock, flags); 69 + 70 + return 0; 71 + } 72 + 73 + static void clk_corediv_disable(struct clk_hw *hwclk) 74 + { 75 + struct clk_corediv *corediv = to_corediv_clk(hwclk); 76 + struct clk_corediv_desc *desc = &corediv->desc; 77 + unsigned long flags = 0; 78 + u32 reg; 79 + 80 + spin_lock_irqsave(&corediv->lock, flags); 81 + 82 + reg = readl(corediv->reg); 83 + reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET); 84 + writel(reg, corediv->reg); 85 + 86 + spin_unlock_irqrestore(&corediv->lock, flags); 87 + } 88 + 89 + static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk, 90 + unsigned long parent_rate) 91 + { 92 + struct clk_corediv *corediv = to_corediv_clk(hwclk); 93 + struct clk_corediv_desc *desc = &corediv->desc; 94 + u32 reg, div; 95 + 96 + reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 97 + div = (reg >> desc->offset) & desc->mask; 98 + return parent_rate / div; 99 + } 100 + 101 + static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate, 102 + unsigned long *parent_rate) 103 + { 104 + /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */ 105 + u32 div; 106 + 107 + div = *parent_rate / rate; 108 + if (div < 4) 109 + div = 4; 110 + else if (div > 6) 111 + div = 8; 112 + 113 + return *parent_rate / div; 114 + } 115 + 116 + static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, 117 + unsigned long parent_rate) 118 + { 119 + struct clk_corediv *corediv = to_corediv_clk(hwclk); 120 + struct clk_corediv_desc *desc = &corediv->desc; 121 + unsigned long flags = 0; 122 + u32 reg, div; 123 + 124 + div = parent_rate / rate; 125 + 126 + spin_lock_irqsave(&corediv->lock, flags); 127 + 128 + /* Write new divider to the divider ratio register */ 129 + reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 130 + reg &= ~(desc->mask << desc->offset); 131 + reg |= (div & desc->mask) << desc->offset; 132 + writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET); 133 + 134 + /* Set reload-force for this clock */ 135 + reg = readl(corediv->reg) | BIT(desc->fieldbit); 136 + writel(reg, corediv->reg); 137 + 138 + /* Now trigger the clock update */ 139 + reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD; 140 + writel(reg, corediv->reg); 141 + 142 + /* 143 + * Wait for clocks to settle down, and then clear all the 144 + * ratios request and the reload request. 145 + */ 146 + udelay(1000); 147 + reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD); 148 + writel(reg, corediv->reg); 149 + udelay(1000); 150 + 151 + spin_unlock_irqrestore(&corediv->lock, flags); 152 + 153 + return 0; 154 + } 155 + 156 + static const struct clk_ops corediv_ops = { 157 + .enable = clk_corediv_enable, 158 + .disable = clk_corediv_disable, 159 + .is_enabled = clk_corediv_is_enabled, 160 + .recalc_rate = clk_corediv_recalc_rate, 161 + .round_rate = clk_corediv_round_rate, 162 + .set_rate = clk_corediv_set_rate, 163 + }; 164 + 165 + static void __init mvebu_corediv_clk_init(struct device_node *node) 166 + { 167 + struct clk_init_data init; 168 + struct clk_corediv *corediv; 169 + struct clk **clks; 170 + void __iomem *base; 171 + const char *parent_name; 172 + const char *clk_name; 173 + int i; 174 + 175 + base = of_iomap(node, 0); 176 + if (WARN_ON(!base)) 177 + return; 178 + 179 + parent_name = of_clk_get_parent_name(node, 0); 180 + 181 + clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc); 182 + 183 + /* clks holds the clock array */ 184 + clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), 185 + GFP_KERNEL); 186 + if (WARN_ON(!clks)) 187 + goto err_unmap; 188 + /* corediv holds the clock specific array */ 189 + corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv), 190 + GFP_KERNEL); 191 + if (WARN_ON(!corediv)) 192 + goto err_free_clks; 193 + 194 + spin_lock_init(&corediv->lock); 195 + 196 + for (i = 0; i < clk_data.clk_num; i++) { 197 + of_property_read_string_index(node, "clock-output-names", 198 + i, &clk_name); 199 + init.num_parents = 1; 200 + init.parent_names = &parent_name; 201 + init.name = clk_name; 202 + init.ops = &corediv_ops; 203 + init.flags = 0; 204 + 205 + corediv[i].desc = mvebu_corediv_desc[i]; 206 + corediv[i].reg = base; 207 + corediv[i].hw.init = &init; 208 + 209 + clks[i] = clk_register(NULL, &corediv[i].hw); 210 + WARN_ON(IS_ERR(clks[i])); 211 + } 212 + 213 + clk_data.clks = clks; 214 + of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data); 215 + return; 216 + 217 + err_free_clks: 218 + kfree(clks); 219 + err_unmap: 220 + iounmap(base); 221 + } 222 + CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock", 223 + mvebu_corediv_clk_init);