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 v6.19 294 lines 6.5 kB view raw
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 struct clk_hw *parent_hw, 148 const struct clk_ops *ops, unsigned long flags) 149{ 150 struct clk_utmi *utmi; 151 struct clk_hw *hw; 152 struct clk_init_data init = {}; 153 int ret; 154 155 if (!(parent_name || parent_hw)) 156 return ERR_PTR(-EINVAL); 157 158 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL); 159 if (!utmi) 160 return ERR_PTR(-ENOMEM); 161 162 init.name = name; 163 init.ops = ops; 164 if (parent_hw) 165 init.parent_hws = (const struct clk_hw **)&parent_hw; 166 else 167 init.parent_names = &parent_name; 168 init.num_parents = 1; 169 init.flags = flags; 170 171 utmi->hw.init = &init; 172 utmi->regmap_pmc = regmap_pmc; 173 utmi->regmap_sfr = regmap_sfr; 174 175 hw = &utmi->hw; 176 ret = clk_hw_register(NULL, &utmi->hw); 177 if (ret) { 178 kfree(utmi); 179 hw = ERR_PTR(ret); 180 } 181 182 return hw; 183} 184 185struct clk_hw * __init 186at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, 187 const char *name, const char *parent_name, 188 struct clk_hw *parent_hw) 189{ 190 return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name, 191 parent_name, parent_hw, &utmi_ops, CLK_SET_RATE_GATE); 192} 193 194static int clk_utmi_sama7g5_prepare(struct clk_hw *hw) 195{ 196 struct clk_utmi *utmi = to_clk_utmi(hw); 197 struct clk_hw *hw_parent; 198 unsigned long parent_rate; 199 unsigned int val; 200 201 hw_parent = clk_hw_get_parent(hw); 202 parent_rate = clk_hw_get_rate(hw_parent); 203 204 switch (parent_rate) { 205 case 16000000: 206 val = 0; 207 break; 208 case 20000000: 209 val = 2; 210 break; 211 case 24000000: 212 val = 3; 213 break; 214 case 32000000: 215 val = 5; 216 break; 217 default: 218 pr_err("UTMICK: unsupported main_xtal rate\n"); 219 return -EINVAL; 220 } 221 222 regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val); 223 224 return 0; 225 226} 227 228static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw) 229{ 230 struct clk_utmi *utmi = to_clk_utmi(hw); 231 struct clk_hw *hw_parent; 232 unsigned long parent_rate; 233 unsigned int val; 234 235 hw_parent = clk_hw_get_parent(hw); 236 parent_rate = clk_hw_get_rate(hw_parent); 237 238 regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val); 239 switch (val & 0x7) { 240 case 0: 241 if (parent_rate == 16000000) 242 return 1; 243 break; 244 case 2: 245 if (parent_rate == 20000000) 246 return 1; 247 break; 248 case 3: 249 if (parent_rate == 24000000) 250 return 1; 251 break; 252 case 5: 253 if (parent_rate == 32000000) 254 return 1; 255 break; 256 default: 257 break; 258 } 259 260 return 0; 261} 262 263static int clk_utmi_sama7g5_save_context(struct clk_hw *hw) 264{ 265 struct clk_utmi *utmi = to_clk_utmi(hw); 266 267 utmi->pms.status = clk_utmi_sama7g5_is_prepared(hw); 268 269 return 0; 270} 271 272static void clk_utmi_sama7g5_restore_context(struct clk_hw *hw) 273{ 274 struct clk_utmi *utmi = to_clk_utmi(hw); 275 276 if (utmi->pms.status) 277 clk_utmi_sama7g5_prepare(hw); 278} 279 280static const struct clk_ops sama7g5_utmi_ops = { 281 .prepare = clk_utmi_sama7g5_prepare, 282 .is_prepared = clk_utmi_sama7g5_is_prepared, 283 .recalc_rate = clk_utmi_recalc_rate, 284 .save_context = clk_utmi_sama7g5_save_context, 285 .restore_context = clk_utmi_sama7g5_restore_context, 286}; 287 288struct clk_hw * __init 289at91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name, 290 const char *parent_name, struct clk_hw *parent_hw) 291{ 292 return at91_clk_register_utmi_internal(regmap_pmc, NULL, name, 293 parent_name, parent_hw, &sama7g5_utmi_ops, 0); 294}