1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2012 Freescale Semiconductor, Inc.
6 #include <linux/clk-provider.h>
9 #include <linux/slab.h>
13 * struct clk_ref - mxs reference clock
14 * @hw: clk_hw for the reference clock
15 * @reg: register address
16 * @idx: the index of the reference clock within the same register
18 * The mxs reference clock sources from pll. Every 4 reference clocks share
19 * one register space, and @idx is used to identify them. Each reference
20 * clock has a gate control and a fractional * divider. The rate is calculated
21 * as pll rate * (18 / FRAC), where FRAC = 18 ~ 35.
29 #define to_clk_ref(_hw) container_of(_hw, struct clk_ref, hw)
31 static int clk_ref_enable(struct clk_hw
*hw
)
33 struct clk_ref
*ref
= to_clk_ref(hw
);
35 writel_relaxed(1 << ((ref
->idx
+ 1) * 8 - 1), ref
->reg
+ CLR
);
40 static void clk_ref_disable(struct clk_hw
*hw
)
42 struct clk_ref
*ref
= to_clk_ref(hw
);
44 writel_relaxed(1 << ((ref
->idx
+ 1) * 8 - 1), ref
->reg
+ SET
);
47 static unsigned long clk_ref_recalc_rate(struct clk_hw
*hw
,
48 unsigned long parent_rate
)
50 struct clk_ref
*ref
= to_clk_ref(hw
);
51 u64 tmp
= parent_rate
;
52 u8 frac
= (readl_relaxed(ref
->reg
) >> (ref
->idx
* 8)) & 0x3f;
60 static long clk_ref_round_rate(struct clk_hw
*hw
, unsigned long rate
,
63 unsigned long parent_rate
= *prate
;
64 u64 tmp
= parent_rate
;
67 tmp
= tmp
* 18 + rate
/ 2;
83 static int clk_ref_set_rate(struct clk_hw
*hw
, unsigned long rate
,
84 unsigned long parent_rate
)
86 struct clk_ref
*ref
= to_clk_ref(hw
);
88 u64 tmp
= parent_rate
;
90 u8 frac
, shift
= ref
->idx
* 8;
92 tmp
= tmp
* 18 + rate
/ 2;
101 spin_lock_irqsave(&mxs_lock
, flags
);
103 val
= readl_relaxed(ref
->reg
);
104 val
&= ~(0x3f << shift
);
105 val
|= frac
<< shift
;
106 writel_relaxed(val
, ref
->reg
);
108 spin_unlock_irqrestore(&mxs_lock
, flags
);
113 static const struct clk_ops clk_ref_ops
= {
114 .enable
= clk_ref_enable
,
115 .disable
= clk_ref_disable
,
116 .recalc_rate
= clk_ref_recalc_rate
,
117 .round_rate
= clk_ref_round_rate
,
118 .set_rate
= clk_ref_set_rate
,
121 struct clk
*mxs_clk_ref(const char *name
, const char *parent_name
,
122 void __iomem
*reg
, u8 idx
)
126 struct clk_init_data init
;
128 ref
= kzalloc(sizeof(*ref
), GFP_KERNEL
);
130 return ERR_PTR(-ENOMEM
);
133 init
.ops
= &clk_ref_ops
;
135 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
136 init
.num_parents
= (parent_name
? 1 : 0);
140 ref
->hw
.init
= &init
;
142 clk
= clk_register(NULL
, &ref
->hw
);