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 UTMI_FIXED_MUL 40 21 22 struct clk_utmi { 23 struct clk_hw hw; 24 struct regmap *regmap; 25 }; 26 27 #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) 28 29 static inline bool clk_utmi_ready(struct regmap *regmap) 30 { 31 unsigned int status; 32 33 regmap_read(regmap, AT91_PMC_SR, &status); 34 35 return status & AT91_PMC_LOCKU; 36 } 37 38 static int clk_utmi_prepare(struct clk_hw *hw) 39 { 40 struct clk_utmi *utmi = to_clk_utmi(hw); 41 unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | 42 AT91_PMC_BIASEN; 43 44 regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr); 45 46 while (!clk_utmi_ready(utmi->regmap)) 47 cpu_relax(); 48 49 return 0; 50 } 51 52 static int clk_utmi_is_prepared(struct clk_hw *hw) 53 { 54 struct clk_utmi *utmi = to_clk_utmi(hw); 55 56 return clk_utmi_ready(utmi->regmap); 57 } 58 59 static void clk_utmi_unprepare(struct clk_hw *hw) 60 { 61 struct clk_utmi *utmi = to_clk_utmi(hw); 62 63 regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0); 64 } 65 66 static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, 67 unsigned long parent_rate) 68 { 69 /* UTMI clk is a fixed clk multiplier */ 70 return parent_rate * UTMI_FIXED_MUL; 71 } 72 73 static const struct clk_ops utmi_ops = { 74 .prepare = clk_utmi_prepare, 75 .unprepare = clk_utmi_unprepare, 76 .is_prepared = clk_utmi_is_prepared, 77 .recalc_rate = clk_utmi_recalc_rate, 78 }; 79 80 static struct clk * __init 81 at91_clk_register_utmi(struct regmap *regmap, 82 const char *name, const char *parent_name) 83 { 84 struct clk_utmi *utmi; 85 struct clk *clk = NULL; 86 struct clk_init_data init; 87 88 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); 89 if (!utmi) 90 return ERR_PTR(-ENOMEM); 91 92 init.name = name; 93 init.ops = &utmi_ops; 94 init.parent_names = parent_name ? &parent_name : NULL; 95 init.num_parents = parent_name ? 1 : 0; 96 init.flags = CLK_SET_RATE_GATE; 97 98 utmi->hw.init = &init; 99 utmi->regmap = regmap; 100 101 clk = clk_register(NULL, &utmi->hw); 102 if (IS_ERR(clk)) 103 kfree(utmi); 104 105 return clk; 106 } 107 108 static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) 109 { 110 struct clk *clk; 111 const char *parent_name; 112 const char *name = np->name; 113 struct regmap *regmap; 114 115 parent_name = of_clk_get_parent_name(np, 0); 116 117 of_property_read_string(np, "clock-output-names", &name); 118 119 regmap = syscon_node_to_regmap(of_get_parent(np)); 120 if (IS_ERR(regmap)) 121 return; 122 123 clk = at91_clk_register_utmi(regmap, name, parent_name); 124 if (IS_ERR(clk)) 125 return; 126 127 of_clk_add_provider(np, of_clk_src_simple_get, clk); 128 return; 129 } 130 CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi", 131 of_at91sam9x5_clk_utmi_setup); 132