295 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 different18 * rate can't be configured.19 */20#define UTMI_RATE 48000000021 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 the51 * FREQ field of the SFR_UTMICKTRIM register to generate properly52 * 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 MAINCK69 * 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 * __init144at91_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 else167 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 * __init186at91_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 * __init289at91_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}295