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 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
);
88 icst
->params
->ref
= parent_rate
;
89 vco
= vco_get(icst
->vcoreg
);
90 icst
->rate
= icst_hz(icst
->params
, vco
);
94 static long icst_round_rate(struct clk_hw
*hw
, unsigned long rate
,
97 struct clk_icst
*icst
= to_icst(hw
);
100 vco
= icst_hz_to_vco(icst
->params
, rate
);
101 return icst_hz(icst
->params
, vco
);
104 static int icst_set_rate(struct clk_hw
*hw
, unsigned long rate
,
105 unsigned long parent_rate
)
107 struct clk_icst
*icst
= to_icst(hw
);
111 icst
->params
->ref
= parent_rate
;
112 vco
= icst_hz_to_vco(icst
->params
, rate
);
113 icst
->rate
= icst_hz(icst
->params
, vco
);
114 vco_set(icst
->lockreg
, icst
->vcoreg
, vco
);
118 static const struct clk_ops icst_ops
= {
119 .recalc_rate
= icst_recalc_rate
,
120 .round_rate
= icst_round_rate
,
121 .set_rate
= icst_set_rate
,
124 struct clk
*icst_clk_register(struct device
*dev
,
125 const struct clk_icst_desc
*desc
,
127 const char *parent_name
,
131 struct clk_icst
*icst
;
132 struct clk_init_data init
;
133 struct icst_params
*pclone
;
135 icst
= kzalloc(sizeof(struct clk_icst
), GFP_KERNEL
);
137 pr_err("could not allocate ICST clock!\n");
138 return ERR_PTR(-ENOMEM
);
141 pclone
= kmemdup(desc
->params
, sizeof(*pclone
), GFP_KERNEL
);
144 pr_err("could not clone ICST params\n");
145 return ERR_PTR(-ENOMEM
);
149 init
.ops
= &icst_ops
;
150 init
.flags
= CLK_IS_ROOT
;
151 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
152 init
.num_parents
= (parent_name
? 1 : 0);
153 icst
->hw
.init
= &init
;
154 icst
->params
= pclone
;
155 icst
->vcoreg
= base
+ desc
->vco_offset
;
156 icst
->lockreg
= base
+ desc
->lock_offset
;
158 clk
= clk_register(dev
, &icst
->hw
);
166 EXPORT_SYMBOL_GPL(icst_clk_register
);