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/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/export.h>
19 #include <linux/err.h>
20 #include <linux/clk-provider.h>
26 * struct clk_icst - ICST VCO clock wrapper
27 * @hw: corresponding clock hardware entry
28 * @vcoreg: VCO register address
29 * @lockreg: VCO lock register address
30 * @params: parameters for this ICST instance
36 void __iomem
*lockreg
;
37 struct icst_params
*params
;
41 #define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
44 * vco_get() - get ICST VCO settings from a certain register
45 * @vcoreg: register containing the VCO settings
47 static struct icst_vco
vco_get(void __iomem
*vcoreg
)
54 vco
.r
= (val
>> 9) & 0x7f;
55 vco
.s
= (val
>> 16) & 03;
60 * vco_set() - commit changes to an ICST VCO
61 * @locreg: register to poke to unlock the VCO for writing
62 * @vcoreg: register containing the VCO settings
63 * @vco: ICST VCO parameters to commit
65 static void vco_set(void __iomem
*lockreg
,
71 val
= readl(vcoreg
) & ~0x7ffff;
72 val
|= vco
.v
| (vco
.r
<< 9) | (vco
.s
<< 16);
74 /* This magic unlocks the VCO so it can be controlled */
75 writel(0xa05f, lockreg
);
77 /* This locks the VCO again */
82 static unsigned long icst_recalc_rate(struct clk_hw
*hw
,
83 unsigned long parent_rate
)
85 struct clk_icst
*icst
= to_icst(hw
);
89 icst
->params
->ref
= parent_rate
;
90 vco
= vco_get(icst
->vcoreg
);
91 icst
->rate
= icst_hz(icst
->params
, vco
);
95 static long icst_round_rate(struct clk_hw
*hw
, unsigned long rate
,
98 struct clk_icst
*icst
= to_icst(hw
);
101 vco
= icst_hz_to_vco(icst
->params
, rate
);
102 return icst_hz(icst
->params
, vco
);
105 static int icst_set_rate(struct clk_hw
*hw
, unsigned long rate
,
106 unsigned long parent_rate
)
108 struct clk_icst
*icst
= to_icst(hw
);
112 icst
->params
->ref
= parent_rate
;
113 vco
= icst_hz_to_vco(icst
->params
, rate
);
114 icst
->rate
= icst_hz(icst
->params
, vco
);
115 vco_set(icst
->lockreg
, icst
->vcoreg
, vco
);
119 static const struct clk_ops icst_ops
= {
120 .recalc_rate
= icst_recalc_rate
,
121 .round_rate
= icst_round_rate
,
122 .set_rate
= icst_set_rate
,
125 struct clk
*icst_clk_register(struct device
*dev
,
126 const struct clk_icst_desc
*desc
,
128 const char *parent_name
,
132 struct clk_icst
*icst
;
133 struct clk_init_data init
;
134 struct icst_params
*pclone
;
136 icst
= kzalloc(sizeof(struct clk_icst
), GFP_KERNEL
);
138 pr_err("could not allocate ICST clock!\n");
139 return ERR_PTR(-ENOMEM
);
142 pclone
= kmemdup(desc
->params
, sizeof(*pclone
), GFP_KERNEL
);
145 pr_err("could not clone ICST params\n");
146 return ERR_PTR(-ENOMEM
);
150 init
.ops
= &icst_ops
;
151 init
.flags
= CLK_IS_ROOT
;
152 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
153 init
.num_parents
= (parent_name
? 1 : 0);
154 icst
->hw
.init
= &init
;
155 icst
->params
= pclone
;
156 icst
->vcoreg
= base
+ desc
->vco_offset
;
157 icst
->lockreg
= base
+ desc
->lock_offset
;
159 clk
= clk_register(dev
, &icst
->hw
);
167 EXPORT_SYMBOL_GPL(icst_clk_register
);