clk-utmi.c (6244B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 4 */ 5 6#include <linux/clk-provider.h> 7#include <linux/clkdev.h> 8#include <linux/clk/at91_pmc.h> 9#include <linux/of.h> 10#include <linux/mfd/syscon.h> 11#include <linux/regmap.h> 12#include <soc/at91/atmel-sfr.h> 13 14#include "pmc.h" 15 16/* 17 * The purpose of this clock is to generate a 480 MHz signal. A different 18 * rate can't be configured. 19 */ 20#define UTMI_RATE 480000000 21 22struct clk_utmi { 23 struct clk_hw hw; 24 struct regmap *regmap_pmc; 25 struct regmap *regmap_sfr; 26 struct at91_clk_pms pms; 27}; 28 29#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) 30 31static inline bool clk_utmi_ready(struct regmap *regmap) 32{ 33 unsigned int status; 34 35 regmap_read(regmap, AT91_PMC_SR, &status); 36 37 return status & AT91_PMC_LOCKU; 38} 39 40static int clk_utmi_prepare(struct clk_hw *hw) 41{ 42 struct clk_hw *hw_parent; 43 struct clk_utmi *utmi = to_clk_utmi(hw); 44 unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | 45 AT91_PMC_BIASEN; 46 unsigned int utmi_ref_clk_freq; 47 unsigned long parent_rate; 48 49 /* 50 * If mainck rate is different from 12 MHz, we have to configure the 51 * FREQ field of the SFR_UTMICKTRIM register to generate properly 52 * the utmi clock. 53 */ 54 hw_parent = clk_hw_get_parent(hw); 55 parent_rate = clk_hw_get_rate(hw_parent); 56 57 switch (parent_rate) { 58 case 12000000: 59 utmi_ref_clk_freq = 0; 60 break; 61 case 16000000: 62 utmi_ref_clk_freq = 1; 63 break; 64 case 24000000: 65 utmi_ref_clk_freq = 2; 66 break; 67 /* 68 * Not supported on SAMA5D2 but it's not an issue since MAINCK 69 * maximum value is 24 MHz. 70 */ 71 case 48000000: 72 utmi_ref_clk_freq = 3; 73 break; 74 default: 75 pr_err("UTMICK: unsupported mainck rate\n"); 76 return -EINVAL; 77 } 78 79 if (utmi->regmap_sfr) { 80 regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM, 81 AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq); 82 } else if (utmi_ref_clk_freq) { 83 pr_err("UTMICK: sfr node required\n"); 84 return -EINVAL; 85 } 86 87 regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, uckr, uckr); 88 89 while (!clk_utmi_ready(utmi->regmap_pmc)) 90 cpu_relax(); 91 92 return 0; 93} 94 95static int clk_utmi_is_prepared(struct clk_hw *hw) 96{ 97 struct clk_utmi *utmi = to_clk_utmi(hw); 98 99 return clk_utmi_ready(utmi->regmap_pmc); 100} 101 102static void clk_utmi_unprepare(struct clk_hw *hw) 103{ 104 struct clk_utmi *utmi = to_clk_utmi(hw); 105 106 regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, 107 AT91_PMC_UPLLEN, 0); 108} 109 110static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, 111 unsigned long parent_rate) 112{ 113 /* UTMI clk rate is fixed. */ 114 return UTMI_RATE; 115} 116 117static int clk_utmi_save_context(struct clk_hw *hw) 118{ 119 struct clk_utmi *utmi = to_clk_utmi(hw); 120 121 utmi->pms.status = clk_utmi_is_prepared(hw); 122 123 return 0; 124} 125 126static void clk_utmi_restore_context(struct clk_hw *hw) 127{ 128 struct clk_utmi *utmi = to_clk_utmi(hw); 129 130 if (utmi->pms.status) 131 clk_utmi_prepare(hw); 132} 133 134static const struct clk_ops utmi_ops = { 135 .prepare = clk_utmi_prepare, 136 .unprepare = clk_utmi_unprepare, 137 .is_prepared = clk_utmi_is_prepared, 138 .recalc_rate = clk_utmi_recalc_rate, 139 .save_context = clk_utmi_save_context, 140 .restore_context = clk_utmi_restore_context, 141}; 142 143static struct clk_hw * __init 144at91_clk_register_utmi_internal(struct regmap *regmap_pmc, 145 struct regmap *regmap_sfr, 146 const char *name, const char *parent_name, 147 const struct clk_ops *ops, unsigned long flags) 148{ 149 struct clk_utmi *utmi; 150 struct clk_hw *hw; 151 struct clk_init_data init; 152 int ret; 153 154 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); 155 if (!utmi) 156 return ERR_PTR(-ENOMEM); 157 158 init.name = name; 159 init.ops = ops; 160 init.parent_names = parent_name ? &parent_name : NULL; 161 init.num_parents = parent_name ? 1 : 0; 162 init.flags = flags; 163 164 utmi->hw.init = &init; 165 utmi->regmap_pmc = regmap_pmc; 166 utmi->regmap_sfr = regmap_sfr; 167 168 hw = &utmi->hw; 169 ret = clk_hw_register(NULL, &utmi->hw); 170 if (ret) { 171 kfree(utmi); 172 hw = ERR_PTR(ret); 173 } 174 175 return hw; 176} 177 178struct clk_hw * __init 179at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, 180 const char *name, const char *parent_name) 181{ 182 return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name, 183 parent_name, &utmi_ops, CLK_SET_RATE_GATE); 184} 185 186static int clk_utmi_sama7g5_prepare(struct clk_hw *hw) 187{ 188 struct clk_utmi *utmi = to_clk_utmi(hw); 189 struct clk_hw *hw_parent; 190 unsigned long parent_rate; 191 unsigned int val; 192 193 hw_parent = clk_hw_get_parent(hw); 194 parent_rate = clk_hw_get_rate(hw_parent); 195 196 switch (parent_rate) { 197 case 16000000: 198 val = 0; 199 break; 200 case 20000000: 201 val = 2; 202 break; 203 case 24000000: 204 val = 3; 205 break; 206 case 32000000: 207 val = 5; 208 break; 209 default: 210 pr_err("UTMICK: unsupported main_xtal rate\n"); 211 return -EINVAL; 212 } 213 214 regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val); 215 216 return 0; 217 218} 219 220static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw) 221{ 222 struct clk_utmi *utmi = to_clk_utmi(hw); 223 struct clk_hw *hw_parent; 224 unsigned long parent_rate; 225 unsigned int val; 226 227 hw_parent = clk_hw_get_parent(hw); 228 parent_rate = clk_hw_get_rate(hw_parent); 229 230 regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val); 231 switch (val & 0x7) { 232 case 0: 233 if (parent_rate == 16000000) 234 return 1; 235 break; 236 case 2: 237 if (parent_rate == 20000000) 238 return 1; 239 break; 240 case 3: 241 if (parent_rate == 24000000) 242 return 1; 243 break; 244 case 5: 245 if (parent_rate == 32000000) 246 return 1; 247 break; 248 default: 249 break; 250 } 251 252 return 0; 253} 254 255static int clk_utmi_sama7g5_save_context(struct clk_hw *hw) 256{ 257 struct clk_utmi *utmi = to_clk_utmi(hw); 258 259 utmi->pms.status = clk_utmi_sama7g5_is_prepared(hw); 260 261 return 0; 262} 263 264static void clk_utmi_sama7g5_restore_context(struct clk_hw *hw) 265{ 266 struct clk_utmi *utmi = to_clk_utmi(hw); 267 268 if (utmi->pms.status) 269 clk_utmi_sama7g5_prepare(hw); 270} 271 272static const struct clk_ops sama7g5_utmi_ops = { 273 .prepare = clk_utmi_sama7g5_prepare, 274 .is_prepared = clk_utmi_sama7g5_is_prepared, 275 .recalc_rate = clk_utmi_recalc_rate, 276 .save_context = clk_utmi_sama7g5_save_context, 277 .restore_context = clk_utmi_sama7g5_restore_context, 278}; 279 280struct clk_hw * __init 281at91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name, 282 const char *parent_name) 283{ 284 return at91_clk_register_utmi_internal(regmap_pmc, NULL, name, 285 parent_name, &sama7g5_utmi_ops, 0); 286}