1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018 NVIDIA CORPORATION. All rights reserved.
7 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
8 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
9 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
13 #include <linux/clk-provider.h>
14 #include <linux/err.h>
15 #include <linux/types.h>
19 #define DIV_MASK GENMASK(7, 0)
21 #define MUX_MASK GENMASK(MUX_SHIFT + 2, MUX_SHIFT)
24 #define get_max_div(d) DIV_MASK
25 #define get_div_field(val) ((val) & DIV_MASK)
26 #define get_mux_field(val) (((val) & MUX_MASK) >> MUX_SHIFT)
28 static const char * const mux_sdmmc_parents
[] = {
29 "pll_p", "pll_c4_out2", "pll_c4_out0", "pll_c4_out1", "clk_m"
32 static const u8 mux_lj_idx
[] = {
33 [0] = 0, [1] = 1, [2] = 2, [3] = 5, [4] = 6
36 static const u8 mux_non_lj_idx
[] = {
37 [0] = 0, [1] = 3, [2] = 7, [3] = 4, [4] = 6
40 static u8
clk_sdmmc_mux_get_parent(struct clk_hw
*hw
)
42 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
47 num_parents
= clk_hw_get_num_parents(hw
);
49 val
= readl_relaxed(sdmmc_mux
->reg
);
50 src
= get_mux_field(val
);
51 if (get_div_field(val
))
52 mux_idx
= mux_non_lj_idx
;
56 for (i
= 0; i
< num_parents
; i
++) {
57 if (mux_idx
[i
] == src
)
61 WARN(1, "Unknown parent selector %d\n", src
);
66 static int clk_sdmmc_mux_set_parent(struct clk_hw
*hw
, u8 index
)
68 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
72 val
= readl_relaxed(sdmmc_mux
->reg
);
73 if (get_div_field(val
))
74 index
= mux_non_lj_idx
[index
];
76 index
= mux_lj_idx
[index
];
79 val
|= index
<< MUX_SHIFT
;
81 writel(val
, sdmmc_mux
->reg
);
86 static unsigned long clk_sdmmc_mux_recalc_rate(struct clk_hw
*hw
,
87 unsigned long parent_rate
)
89 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
92 u64 rate
= parent_rate
;
94 val
= readl_relaxed(sdmmc_mux
->reg
);
95 div
= get_div_field(val
);
106 static int clk_sdmmc_mux_determine_rate(struct clk_hw
*hw
,
107 struct clk_rate_request
*req
)
109 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
111 unsigned long output_rate
= req
->best_parent_rate
;
113 req
->rate
= max(req
->rate
, req
->min_rate
);
114 req
->rate
= min(req
->rate
, req
->max_rate
);
119 div
= div_frac_get(req
->rate
, output_rate
, 8, 1, sdmmc_mux
->div_flags
);
123 if (sdmmc_mux
->div_flags
& TEGRA_DIVIDER_ROUND_UP
)
124 req
->rate
= DIV_ROUND_UP(output_rate
* SDMMC_MUL
,
127 req
->rate
= output_rate
* SDMMC_MUL
/ (div
+ SDMMC_MUL
);
132 static int clk_sdmmc_mux_set_rate(struct clk_hw
*hw
, unsigned long rate
,
133 unsigned long parent_rate
)
135 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
137 unsigned long flags
= 0;
141 div
= div_frac_get(rate
, parent_rate
, 8, 1, sdmmc_mux
->div_flags
);
146 spin_lock_irqsave(sdmmc_mux
->lock
, flags
);
148 src
= clk_sdmmc_mux_get_parent(hw
);
150 src
= mux_non_lj_idx
[src
];
152 src
= mux_lj_idx
[src
];
154 val
= src
<< MUX_SHIFT
;
156 writel(val
, sdmmc_mux
->reg
);
157 fence_udelay(2, sdmmc_mux
->reg
);
160 spin_unlock_irqrestore(sdmmc_mux
->lock
, flags
);
165 static int clk_sdmmc_mux_is_enabled(struct clk_hw
*hw
)
167 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
168 const struct clk_ops
*gate_ops
= sdmmc_mux
->gate_ops
;
169 struct clk_hw
*gate_hw
= &sdmmc_mux
->gate
.hw
;
171 __clk_hw_set_clk(gate_hw
, hw
);
173 return gate_ops
->is_enabled(gate_hw
);
176 static int clk_sdmmc_mux_enable(struct clk_hw
*hw
)
178 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
179 const struct clk_ops
*gate_ops
= sdmmc_mux
->gate_ops
;
180 struct clk_hw
*gate_hw
= &sdmmc_mux
->gate
.hw
;
182 __clk_hw_set_clk(gate_hw
, hw
);
184 return gate_ops
->enable(gate_hw
);
187 static void clk_sdmmc_mux_disable(struct clk_hw
*hw
)
189 struct tegra_sdmmc_mux
*sdmmc_mux
= to_clk_sdmmc_mux(hw
);
190 const struct clk_ops
*gate_ops
= sdmmc_mux
->gate_ops
;
191 struct clk_hw
*gate_hw
= &sdmmc_mux
->gate
.hw
;
193 gate_ops
->disable(gate_hw
);
196 static const struct clk_ops tegra_clk_sdmmc_mux_ops
= {
197 .get_parent
= clk_sdmmc_mux_get_parent
,
198 .set_parent
= clk_sdmmc_mux_set_parent
,
199 .determine_rate
= clk_sdmmc_mux_determine_rate
,
200 .recalc_rate
= clk_sdmmc_mux_recalc_rate
,
201 .set_rate
= clk_sdmmc_mux_set_rate
,
202 .is_enabled
= clk_sdmmc_mux_is_enabled
,
203 .enable
= clk_sdmmc_mux_enable
,
204 .disable
= clk_sdmmc_mux_disable
,
207 struct clk
*tegra_clk_register_sdmmc_mux_div(const char *name
,
208 void __iomem
*clk_base
, u32 offset
, u32 clk_num
, u8 div_flags
,
209 unsigned long flags
, void *lock
)
212 struct clk_init_data init
;
213 const struct tegra_clk_periph_regs
*bank
;
214 struct tegra_sdmmc_mux
*sdmmc_mux
;
216 init
.ops
= &tegra_clk_sdmmc_mux_ops
;
219 init
.parent_names
= mux_sdmmc_parents
;
220 init
.num_parents
= ARRAY_SIZE(mux_sdmmc_parents
);
222 bank
= get_reg_bank(clk_num
);
224 return ERR_PTR(-EINVAL
);
226 sdmmc_mux
= kzalloc(sizeof(*sdmmc_mux
), GFP_KERNEL
);
228 return ERR_PTR(-ENOMEM
);
230 /* Data in .init is copied by clk_register(), so stack variable OK */
231 sdmmc_mux
->hw
.init
= &init
;
232 sdmmc_mux
->reg
= clk_base
+ offset
;
233 sdmmc_mux
->lock
= lock
;
234 sdmmc_mux
->gate
.clk_base
= clk_base
;
235 sdmmc_mux
->gate
.regs
= bank
;
236 sdmmc_mux
->gate
.enable_refcnt
= periph_clk_enb_refcnt
;
237 sdmmc_mux
->gate
.clk_num
= clk_num
;
238 sdmmc_mux
->gate
.flags
= TEGRA_PERIPH_ON_APB
;
239 sdmmc_mux
->div_flags
= div_flags
;
240 sdmmc_mux
->gate_ops
= &tegra_clk_periph_gate_ops
;
242 clk
= clk_register(NULL
, &sdmmc_mux
->hw
);
248 sdmmc_mux
->gate
.hw
.clk
= clk
;