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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc1 281 lines 6.7 kB view raw
1/* 2 * Copyright 2013 Freescale Semiconductor, Inc. 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 version 2 as 6 * published by the Free Software Foundation. 7 * 8 * clock driver for Freescale PowerPC corenet SoCs. 9 */ 10#include <linux/clk-provider.h> 11#include <linux/io.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/of_address.h> 15#include <linux/of_platform.h> 16#include <linux/of.h> 17#include <linux/slab.h> 18 19struct cmux_clk { 20 struct clk_hw hw; 21 void __iomem *reg; 22 u32 flags; 23}; 24 25#define PLL_KILL BIT(31) 26#define CLKSEL_SHIFT 27 27#define CLKSEL_ADJUST BIT(0) 28#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw) 29 30static void __iomem *base; 31static unsigned int clocks_per_pll; 32 33static int cmux_set_parent(struct clk_hw *hw, u8 idx) 34{ 35 struct cmux_clk *clk = to_cmux_clk(hw); 36 u32 clksel; 37 38 clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll; 39 if (clk->flags & CLKSEL_ADJUST) 40 clksel += 8; 41 clksel = (clksel & 0xf) << CLKSEL_SHIFT; 42 iowrite32be(clksel, clk->reg); 43 44 return 0; 45} 46 47static u8 cmux_get_parent(struct clk_hw *hw) 48{ 49 struct cmux_clk *clk = to_cmux_clk(hw); 50 u32 clksel; 51 52 clksel = ioread32be(clk->reg); 53 clksel = (clksel >> CLKSEL_SHIFT) & 0xf; 54 if (clk->flags & CLKSEL_ADJUST) 55 clksel -= 8; 56 clksel = (clksel >> 2) * clocks_per_pll + clksel % 4; 57 58 return clksel; 59} 60 61const struct clk_ops cmux_ops = { 62 .get_parent = cmux_get_parent, 63 .set_parent = cmux_set_parent, 64}; 65 66static void __init core_mux_init(struct device_node *np) 67{ 68 struct clk *clk; 69 struct clk_init_data init; 70 struct cmux_clk *cmux_clk; 71 struct device_node *node; 72 int rc, count, i; 73 u32 offset; 74 const char *clk_name; 75 const char **parent_names; 76 77 rc = of_property_read_u32(np, "reg", &offset); 78 if (rc) { 79 pr_err("%s: could not get reg property\n", np->name); 80 return; 81 } 82 83 /* get the input clock source count */ 84 count = of_property_count_strings(np, "clock-names"); 85 if (count < 0) { 86 pr_err("%s: get clock count error\n", np->name); 87 return; 88 } 89 parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL); 90 if (!parent_names) { 91 pr_err("%s: could not allocate parent_names\n", __func__); 92 return; 93 } 94 95 for (i = 0; i < count; i++) 96 parent_names[i] = of_clk_get_parent_name(np, i); 97 98 cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL); 99 if (!cmux_clk) { 100 pr_err("%s: could not allocate cmux_clk\n", __func__); 101 goto err_name; 102 } 103 cmux_clk->reg = base + offset; 104 105 node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen"); 106 if (node && (offset >= 0x80)) 107 cmux_clk->flags = CLKSEL_ADJUST; 108 109 rc = of_property_read_string_index(np, "clock-output-names", 110 0, &clk_name); 111 if (rc) { 112 pr_err("%s: read clock names error\n", np->name); 113 goto err_clk; 114 } 115 116 init.name = clk_name; 117 init.ops = &cmux_ops; 118 init.parent_names = parent_names; 119 init.num_parents = count; 120 init.flags = 0; 121 cmux_clk->hw.init = &init; 122 123 clk = clk_register(NULL, &cmux_clk->hw); 124 if (IS_ERR(clk)) { 125 pr_err("%s: could not register clock\n", clk_name); 126 goto err_clk; 127 } 128 129 rc = of_clk_add_provider(np, of_clk_src_simple_get, clk); 130 if (rc) { 131 pr_err("Could not register clock provider for node:%s\n", 132 np->name); 133 goto err_clk; 134 } 135 goto err_name; 136 137err_clk: 138 kfree(cmux_clk); 139err_name: 140 /* free *_names because they are reallocated when registered */ 141 kfree(parent_names); 142} 143 144static void __init core_pll_init(struct device_node *np) 145{ 146 u32 offset, mult; 147 int i, rc, count; 148 const char *clk_name, *parent_name; 149 struct clk_onecell_data *onecell_data; 150 struct clk **subclks; 151 152 rc = of_property_read_u32(np, "reg", &offset); 153 if (rc) { 154 pr_err("%s: could not get reg property\n", np->name); 155 return; 156 } 157 158 /* get the multiple of PLL */ 159 mult = ioread32be(base + offset); 160 161 /* check if this PLL is disabled */ 162 if (mult & PLL_KILL) { 163 pr_debug("PLL:%s is disabled\n", np->name); 164 return; 165 } 166 mult = (mult >> 1) & 0x3f; 167 168 parent_name = of_clk_get_parent_name(np, 0); 169 if (!parent_name) { 170 pr_err("PLL: %s must have a parent\n", np->name); 171 return; 172 } 173 174 count = of_property_count_strings(np, "clock-output-names"); 175 if (count < 0 || count > 4) { 176 pr_err("%s: clock is not supported\n", np->name); 177 return; 178 } 179 180 /* output clock number per PLL */ 181 clocks_per_pll = count; 182 183 subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL); 184 if (!subclks) { 185 pr_err("%s: could not allocate subclks\n", __func__); 186 return; 187 } 188 189 onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); 190 if (!onecell_data) { 191 pr_err("%s: could not allocate onecell_data\n", __func__); 192 goto err_clks; 193 } 194 195 for (i = 0; i < count; i++) { 196 rc = of_property_read_string_index(np, "clock-output-names", 197 i, &clk_name); 198 if (rc) { 199 pr_err("%s: could not get clock names\n", np->name); 200 goto err_cell; 201 } 202 203 /* 204 * when count == 4, there are 4 output clocks: 205 * /1, /2, /3, /4 respectively 206 * when count < 4, there are at least 2 output clocks: 207 * /1, /2, (/4, if count == 3) respectively. 208 */ 209 if (count == 4) 210 subclks[i] = clk_register_fixed_factor(NULL, clk_name, 211 parent_name, 0, mult, 1 + i); 212 else 213 214 subclks[i] = clk_register_fixed_factor(NULL, clk_name, 215 parent_name, 0, mult, 1 << i); 216 217 if (IS_ERR(subclks[i])) { 218 pr_err("%s: could not register clock\n", clk_name); 219 goto err_cell; 220 } 221 } 222 223 onecell_data->clks = subclks; 224 onecell_data->clk_num = count; 225 226 rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data); 227 if (rc) { 228 pr_err("Could not register clk provider for node:%s\n", 229 np->name); 230 goto err_cell; 231 } 232 233 return; 234err_cell: 235 kfree(onecell_data); 236err_clks: 237 kfree(subclks); 238} 239 240static const struct of_device_id clk_match[] __initconst = { 241 { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, 242 { .compatible = "fsl,core-pll-clock", .data = core_pll_init, }, 243 { .compatible = "fsl,core-mux-clock", .data = core_mux_init, }, 244 {} 245}; 246 247static int __init ppc_corenet_clk_probe(struct platform_device *pdev) 248{ 249 struct device_node *np; 250 251 np = pdev->dev.of_node; 252 base = of_iomap(np, 0); 253 if (!base) { 254 dev_err(&pdev->dev, "iomap error\n"); 255 return -ENOMEM; 256 } 257 of_clk_init(clk_match); 258 259 return 0; 260} 261 262static const struct of_device_id ppc_clk_ids[] __initconst = { 263 { .compatible = "fsl,qoriq-clockgen-1.0", }, 264 { .compatible = "fsl,qoriq-clockgen-2.0", }, 265 {} 266}; 267 268static struct platform_driver ppc_corenet_clk_driver = { 269 .driver = { 270 .name = "ppc_corenet_clock", 271 .owner = THIS_MODULE, 272 .of_match_table = ppc_clk_ids, 273 }, 274 .probe = ppc_corenet_clk_probe, 275}; 276 277static int __init ppc_corenet_clk_init(void) 278{ 279 return platform_driver_register(&ppc_corenet_clk_driver); 280} 281subsys_initcall(ppc_corenet_clk_init);