2 * Driver for the ICST307 VCO clock found in the ARM Reference designs.
3 * We wrap the custom interface from <asm/hardware/icst.h> into the generic
6 * Copyright (C) 2012 Linus Walleij
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * TODO: when all ARM reference designs are migrated to generic clocks, the
13 * ICST clock code from the ARM tree should probably be merged into this
16 #include <linux/clk.h>
17 #include <linux/clkdev.h>
18 #include <linux/err.h>
19 #include <linux/clk-provider.h>
25 * struct clk_icst - ICST VCO clock wrapper
26 * @hw: corresponding clock hardware entry
27 * @vcoreg: VCO register address
28 * @lockreg: VCO lock register address
29 * @params: parameters for this ICST instance
35 void __iomem
*lockreg
;
36 const struct icst_params
*params
;
40 #define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
43 * vco_get() - get ICST VCO settings from a certain register
44 * @vcoreg: register containing the VCO settings
46 static struct icst_vco
vco_get(void __iomem
*vcoreg
)
53 vco
.r
= (val
>> 9) & 0x7f;
54 vco
.s
= (val
>> 16) & 03;
59 * vco_set() - commit changes to an ICST VCO
60 * @locreg: register to poke to unlock the VCO for writing
61 * @vcoreg: register containing the VCO settings
62 * @vco: ICST VCO parameters to commit
64 static void vco_set(void __iomem
*lockreg
,
70 val
= readl(vcoreg
) & ~0x7ffff;
71 val
|= vco
.v
| (vco
.r
<< 9) | (vco
.s
<< 16);
73 /* This magic unlocks the VCO so it can be controlled */
74 writel(0xa05f, lockreg
);
76 /* This locks the VCO again */
81 static unsigned long icst_recalc_rate(struct clk_hw
*hw
,
82 unsigned long parent_rate
)
84 struct clk_icst
*icst
= to_icst(hw
);
87 vco
= vco_get(icst
->vcoreg
);
88 icst
->rate
= icst_hz(icst
->params
, vco
);
92 static long icst_round_rate(struct clk_hw
*hw
, unsigned long rate
,
95 struct clk_icst
*icst
= to_icst(hw
);
98 vco
= icst_hz_to_vco(icst
->params
, rate
);
99 return icst_hz(icst
->params
, vco
);
102 static int icst_set_rate(struct clk_hw
*hw
, unsigned long rate
,
103 unsigned long parent_rate
)
105 struct clk_icst
*icst
= to_icst(hw
);
108 vco
= icst_hz_to_vco(icst
->params
, rate
);
109 icst
->rate
= icst_hz(icst
->params
, vco
);
110 vco_set(icst
->lockreg
, icst
->vcoreg
, vco
);
114 static const struct clk_ops icst_ops
= {
115 .recalc_rate
= icst_recalc_rate
,
116 .round_rate
= icst_round_rate
,
117 .set_rate
= icst_set_rate
,
120 struct clk
*icst_clk_register(struct device
*dev
,
121 const struct clk_icst_desc
*desc
,
126 struct clk_icst
*icst
;
127 struct clk_init_data init
;
129 icst
= kzalloc(sizeof(struct clk_icst
), GFP_KERNEL
);
131 pr_err("could not allocate ICST clock!\n");
132 return ERR_PTR(-ENOMEM
);
135 init
.ops
= &icst_ops
;
136 init
.flags
= CLK_IS_ROOT
;
137 init
.parent_names
= NULL
;
138 init
.num_parents
= 0;
139 icst
->hw
.init
= &init
;
140 icst
->params
= desc
->params
;
141 icst
->vcoreg
= base
+ desc
->vco_offset
;
142 icst
->lockreg
= base
+ desc
->lock_offset
;
144 clk
= clk_register(dev
, &icst
->hw
);