1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
291b87a47SLinus Walleij /*
391b87a47SLinus Walleij * Driver for the ICST307 VCO clock found in the ARM Reference designs.
491b87a47SLinus Walleij * We wrap the custom interface from <asm/hardware/icst.h> into the generic
591b87a47SLinus Walleij * clock framework.
691b87a47SLinus Walleij *
7d430819dSLinus Walleij * Copyright (C) 2012-2015 Linus Walleij
8401301ccSLinus Walleij *
991b87a47SLinus Walleij * TODO: when all ARM reference designs are migrated to generic clocks, the
1091b87a47SLinus Walleij * ICST clock code from the ARM tree should probably be merged into this
1191b87a47SLinus Walleij * file.
1291b87a47SLinus Walleij */
136d31e3b2SStephen Boyd #include <linux/kernel.h>
146d31e3b2SStephen Boyd #include <linux/slab.h>
156d31e3b2SStephen Boyd #include <linux/export.h>
1691b87a47SLinus Walleij #include <linux/err.h>
1791b87a47SLinus Walleij #include <linux/clk-provider.h>
187a9ad671SLinus Walleij #include <linux/io.h>
19179c8fb3SLinus Walleij #include <linux/regmap.h>
20384d977dSLinus Walleij #include <linux/mfd/syscon.h>
2191b87a47SLinus Walleij
22ba3fae06SLinus Walleij #include "icst.h"
2391b87a47SLinus Walleij #include "clk-icst.h"
2491b87a47SLinus Walleij
25179c8fb3SLinus Walleij /* Magic unlocking token used on all Versatile boards */
26179c8fb3SLinus Walleij #define VERSATILE_LOCK_VAL 0xA05F
27179c8fb3SLinus Walleij
285e23c593SLinus Walleij #define VERSATILE_AUX_OSC_BITS 0x7FFFF
295e23c593SLinus Walleij #define INTEGRATOR_AP_CM_BITS 0xFF
30fa62e10dSLinus Walleij #define INTEGRATOR_AP_SYS_BITS 0xFF
315e23c593SLinus Walleij #define INTEGRATOR_CP_CM_CORE_BITS 0x7FF
325e23c593SLinus Walleij #define INTEGRATOR_CP_CM_MEM_BITS 0x7FF000
335e23c593SLinus Walleij
34fa62e10dSLinus Walleij #define INTEGRATOR_AP_PCI_25_33_MHZ BIT(8)
35fa62e10dSLinus Walleij
365e23c593SLinus Walleij /**
3791b87a47SLinus Walleij * struct clk_icst - ICST VCO clock wrapper
3891b87a47SLinus Walleij * @hw: corresponding clock hardware entry
390c1d46d3SLee Jones * @map: register map
400c1d46d3SLee Jones * @vcoreg_off: VCO register address
410c1d46d3SLee Jones * @lockreg_off: VCO lock register address
4291b87a47SLinus Walleij * @params: parameters for this ICST instance
4391b87a47SLinus Walleij * @rate: current rate
445e23c593SLinus Walleij * @ctype: the type of control register for the ICST
4591b87a47SLinus Walleij */
4691b87a47SLinus Walleij struct clk_icst {
4791b87a47SLinus Walleij struct clk_hw hw;
48179c8fb3SLinus Walleij struct regmap *map;
49179c8fb3SLinus Walleij u32 vcoreg_off;
50179c8fb3SLinus Walleij u32 lockreg_off;
51a183da63SLinus Walleij struct icst_params *params;
5291b87a47SLinus Walleij unsigned long rate;
535e23c593SLinus Walleij enum icst_control_type ctype;
5491b87a47SLinus Walleij };
5591b87a47SLinus Walleij
5691b87a47SLinus Walleij #define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
5791b87a47SLinus Walleij
587a9ad671SLinus Walleij /**
59179c8fb3SLinus Walleij * vco_get() - get ICST VCO settings from a certain ICST
60179c8fb3SLinus Walleij * @icst: the ICST clock to get
61179c8fb3SLinus Walleij * @vco: the VCO struct to return the value in
627a9ad671SLinus Walleij */
vco_get(struct clk_icst * icst,struct icst_vco * vco)63179c8fb3SLinus Walleij static int vco_get(struct clk_icst *icst, struct icst_vco *vco)
647a9ad671SLinus Walleij {
657a9ad671SLinus Walleij u32 val;
66179c8fb3SLinus Walleij int ret;
677a9ad671SLinus Walleij
68179c8fb3SLinus Walleij ret = regmap_read(icst->map, icst->vcoreg_off, &val);
69179c8fb3SLinus Walleij if (ret)
70179c8fb3SLinus Walleij return ret;
715e23c593SLinus Walleij
725e23c593SLinus Walleij /*
735e23c593SLinus Walleij * The Integrator/AP core clock can only access the low eight
745e23c593SLinus Walleij * bits of the v PLL divider. Bit 8 is tied low and always zero,
755e23c593SLinus Walleij * r is hardwired to 22 and output divider s is hardwired to 1
765e23c593SLinus Walleij * (divide by 2) according to the document
775e23c593SLinus Walleij * "Integrator CM926EJ-S, CM946E-S, CM966E-S, CM1026EJ-S and
785e23c593SLinus Walleij * CM1136JF-S User Guide" ARM DUI 0138E, page 3-13 thru 3-14.
795e23c593SLinus Walleij */
805e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_CM) {
815e23c593SLinus Walleij vco->v = val & INTEGRATOR_AP_CM_BITS;
825e23c593SLinus Walleij vco->r = 22;
835e23c593SLinus Walleij vco->s = 1;
845e23c593SLinus Walleij return 0;
855e23c593SLinus Walleij }
865e23c593SLinus Walleij
875e23c593SLinus Walleij /*
88fa62e10dSLinus Walleij * The Integrator/AP system clock on the base board can only
89fa62e10dSLinus Walleij * access the low eight bits of the v PLL divider. Bit 8 is tied low
90fa62e10dSLinus Walleij * and always zero, r is hardwired to 46, and the output divider is
91fa62e10dSLinus Walleij * hardwired to 3 (divide by 4) according to the document
92fa62e10dSLinus Walleij * "Integrator AP ASIC Development Motherboard" ARM DUI 0098B,
93fa62e10dSLinus Walleij * page 3-16.
94fa62e10dSLinus Walleij */
95fa62e10dSLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_SYS) {
96fa62e10dSLinus Walleij vco->v = val & INTEGRATOR_AP_SYS_BITS;
97fa62e10dSLinus Walleij vco->r = 46;
98fa62e10dSLinus Walleij vco->s = 3;
99fa62e10dSLinus Walleij return 0;
100fa62e10dSLinus Walleij }
101fa62e10dSLinus Walleij
102fa62e10dSLinus Walleij /*
103fa62e10dSLinus Walleij * The Integrator/AP PCI clock is using an odd pattern to create
104fa62e10dSLinus Walleij * the child clock, basically a single bit called DIVX/Y is used
105fa62e10dSLinus Walleij * to select between two different hardwired values: setting the
106fa62e10dSLinus Walleij * bit to 0 yields v = 17, r = 22 and OD = 1, whereas setting the
107fa62e10dSLinus Walleij * bit to 1 yields v = 14, r = 14 and OD = 1 giving the frequencies
108fa62e10dSLinus Walleij * 33 or 25 MHz respectively.
109fa62e10dSLinus Walleij */
110fa62e10dSLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_PCI) {
111fa62e10dSLinus Walleij bool divxy = !!(val & INTEGRATOR_AP_PCI_25_33_MHZ);
112fa62e10dSLinus Walleij
113fa62e10dSLinus Walleij vco->v = divxy ? 17 : 14;
114fa62e10dSLinus Walleij vco->r = divxy ? 22 : 14;
115fa62e10dSLinus Walleij vco->s = 1;
116fa62e10dSLinus Walleij return 0;
117fa62e10dSLinus Walleij }
118fa62e10dSLinus Walleij
119fa62e10dSLinus Walleij /*
1205e23c593SLinus Walleij * The Integrator/CP core clock can access the low eight bits
1215e23c593SLinus Walleij * of the v PLL divider. Bit 8 is tied low and always zero,
1225e23c593SLinus Walleij * r is hardwired to 22 and the output divider s is accessible
1235e23c593SLinus Walleij * in bits 8 thru 10 according to the document
1245e23c593SLinus Walleij * "Integrator/CM940T, CM920T, CM740T, and CM720T User Guide"
1255e23c593SLinus Walleij * ARM DUI 0157A, page 3-20 thru 3-23 and 4-10.
1265e23c593SLinus Walleij */
1275e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) {
1285e23c593SLinus Walleij vco->v = val & 0xFF;
1295e23c593SLinus Walleij vco->r = 22;
1305e23c593SLinus Walleij vco->s = (val >> 8) & 7;
1315e23c593SLinus Walleij return 0;
1325e23c593SLinus Walleij }
1335e23c593SLinus Walleij
1345e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) {
1355e23c593SLinus Walleij vco->v = (val >> 12) & 0xFF;
1365e23c593SLinus Walleij vco->r = 22;
1375e23c593SLinus Walleij vco->s = (val >> 20) & 7;
1385e23c593SLinus Walleij return 0;
1395e23c593SLinus Walleij }
1405e23c593SLinus Walleij
141179c8fb3SLinus Walleij vco->v = val & 0x1ff;
142179c8fb3SLinus Walleij vco->r = (val >> 9) & 0x7f;
143179c8fb3SLinus Walleij vco->s = (val >> 16) & 03;
144179c8fb3SLinus Walleij return 0;
1457a9ad671SLinus Walleij }
1467a9ad671SLinus Walleij
1477a9ad671SLinus Walleij /**
1487a9ad671SLinus Walleij * vco_set() - commit changes to an ICST VCO
149179c8fb3SLinus Walleij * @icst: the ICST clock to set
150179c8fb3SLinus Walleij * @vco: the VCO struct to set the changes from
1517a9ad671SLinus Walleij */
vco_set(struct clk_icst * icst,struct icst_vco vco)152179c8fb3SLinus Walleij static int vco_set(struct clk_icst *icst, struct icst_vco vco)
1537a9ad671SLinus Walleij {
1545e23c593SLinus Walleij u32 mask;
1557a9ad671SLinus Walleij u32 val;
156179c8fb3SLinus Walleij int ret;
1577a9ad671SLinus Walleij
1585e23c593SLinus Walleij /* Mask the bits used by the VCO */
1595e23c593SLinus Walleij switch (icst->ctype) {
1605e23c593SLinus Walleij case ICST_INTEGRATOR_AP_CM:
1615e23c593SLinus Walleij mask = INTEGRATOR_AP_CM_BITS;
1625e23c593SLinus Walleij val = vco.v & 0xFF;
1635e23c593SLinus Walleij if (vco.v & 0x100)
1645e23c593SLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n");
1655e23c593SLinus Walleij if (vco.s != 1)
1665e23c593SLinus Walleij pr_err("ICST error: tried to use VOD != 1\n");
1675e23c593SLinus Walleij if (vco.r != 22)
1685e23c593SLinus Walleij pr_err("ICST error: tried to use RDW != 22\n");
1695e23c593SLinus Walleij break;
170fa62e10dSLinus Walleij case ICST_INTEGRATOR_AP_SYS:
171fa62e10dSLinus Walleij mask = INTEGRATOR_AP_SYS_BITS;
172fa62e10dSLinus Walleij val = vco.v & 0xFF;
173fa62e10dSLinus Walleij if (vco.v & 0x100)
174fa62e10dSLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n");
175fa62e10dSLinus Walleij if (vco.s != 3)
176fa62e10dSLinus Walleij pr_err("ICST error: tried to use VOD != 1\n");
177fa62e10dSLinus Walleij if (vco.r != 46)
178fa62e10dSLinus Walleij pr_err("ICST error: tried to use RDW != 22\n");
179fa62e10dSLinus Walleij break;
1805e23c593SLinus Walleij case ICST_INTEGRATOR_CP_CM_CORE:
1815e23c593SLinus Walleij mask = INTEGRATOR_CP_CM_CORE_BITS; /* Uses 12 bits */
1825e23c593SLinus Walleij val = (vco.v & 0xFF) | vco.s << 8;
1835e23c593SLinus Walleij if (vco.v & 0x100)
1845e23c593SLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n");
1855e23c593SLinus Walleij if (vco.r != 22)
1865e23c593SLinus Walleij pr_err("ICST error: tried to use RDW != 22\n");
1875e23c593SLinus Walleij break;
1885e23c593SLinus Walleij case ICST_INTEGRATOR_CP_CM_MEM:
1895e23c593SLinus Walleij mask = INTEGRATOR_CP_CM_MEM_BITS; /* Uses 12 bits */
1905e23c593SLinus Walleij val = ((vco.v & 0xFF) << 12) | (vco.s << 20);
1915e23c593SLinus Walleij if (vco.v & 0x100)
1925e23c593SLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n");
1935e23c593SLinus Walleij if (vco.r != 22)
1945e23c593SLinus Walleij pr_err("ICST error: tried to use RDW != 22\n");
1955e23c593SLinus Walleij break;
1965e23c593SLinus Walleij default:
1975e23c593SLinus Walleij /* Regular auxilary oscillator */
1985e23c593SLinus Walleij mask = VERSATILE_AUX_OSC_BITS;
1995e23c593SLinus Walleij val = vco.v | (vco.r << 9) | (vco.s << 16);
2005e23c593SLinus Walleij break;
2015e23c593SLinus Walleij }
202df9cd564SLinus Walleij
2035e23c593SLinus Walleij pr_debug("ICST: new val = 0x%08x\n", val);
2047a9ad671SLinus Walleij
2057a9ad671SLinus Walleij /* This magic unlocks the VCO so it can be controlled */
206179c8fb3SLinus Walleij ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL);
207179c8fb3SLinus Walleij if (ret)
208179c8fb3SLinus Walleij return ret;
2095e23c593SLinus Walleij ret = regmap_update_bits(icst->map, icst->vcoreg_off, mask, val);
210179c8fb3SLinus Walleij if (ret)
211179c8fb3SLinus Walleij return ret;
2127a9ad671SLinus Walleij /* This locks the VCO again */
213179c8fb3SLinus Walleij ret = regmap_write(icst->map, icst->lockreg_off, 0);
214179c8fb3SLinus Walleij if (ret)
215179c8fb3SLinus Walleij return ret;
216179c8fb3SLinus Walleij return 0;
2177a9ad671SLinus Walleij }
2187a9ad671SLinus Walleij
icst_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)21991b87a47SLinus Walleij static unsigned long icst_recalc_rate(struct clk_hw *hw,
22091b87a47SLinus Walleij unsigned long parent_rate)
22191b87a47SLinus Walleij {
22291b87a47SLinus Walleij struct clk_icst *icst = to_icst(hw);
22391b87a47SLinus Walleij struct icst_vco vco;
224179c8fb3SLinus Walleij int ret;
22591b87a47SLinus Walleij
226a183da63SLinus Walleij if (parent_rate)
227a183da63SLinus Walleij icst->params->ref = parent_rate;
228179c8fb3SLinus Walleij ret = vco_get(icst, &vco);
229179c8fb3SLinus Walleij if (ret) {
230179c8fb3SLinus Walleij pr_err("ICST: could not get VCO setting\n");
231179c8fb3SLinus Walleij return 0;
232179c8fb3SLinus Walleij }
23391b87a47SLinus Walleij icst->rate = icst_hz(icst->params, vco);
23491b87a47SLinus Walleij return icst->rate;
23591b87a47SLinus Walleij }
23691b87a47SLinus Walleij
icst_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)23791b87a47SLinus Walleij static long icst_round_rate(struct clk_hw *hw, unsigned long rate,
23891b87a47SLinus Walleij unsigned long *prate)
23991b87a47SLinus Walleij {
24091b87a47SLinus Walleij struct clk_icst *icst = to_icst(hw);
24191b87a47SLinus Walleij struct icst_vco vco;
24291b87a47SLinus Walleij
2435e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_CM ||
2445e23c593SLinus Walleij icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) {
2455e23c593SLinus Walleij if (rate <= 12000000)
2465e23c593SLinus Walleij return 12000000;
2475e23c593SLinus Walleij if (rate >= 160000000)
2485e23c593SLinus Walleij return 160000000;
2495e23c593SLinus Walleij /* Slam to closest megahertz */
2505e23c593SLinus Walleij return DIV_ROUND_CLOSEST(rate, 1000000) * 1000000;
2515e23c593SLinus Walleij }
2525e23c593SLinus Walleij
2535e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) {
2545e23c593SLinus Walleij if (rate <= 6000000)
2555e23c593SLinus Walleij return 6000000;
2565e23c593SLinus Walleij if (rate >= 66000000)
2575e23c593SLinus Walleij return 66000000;
2585e23c593SLinus Walleij /* Slam to closest 0.5 megahertz */
2595e23c593SLinus Walleij return DIV_ROUND_CLOSEST(rate, 500000) * 500000;
2605e23c593SLinus Walleij }
2615e23c593SLinus Walleij
262fa62e10dSLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_SYS) {
263fa62e10dSLinus Walleij /* Divides between 3 and 50 MHz in steps of 0.25 MHz */
264fa62e10dSLinus Walleij if (rate <= 3000000)
265fa62e10dSLinus Walleij return 3000000;
266fa62e10dSLinus Walleij if (rate >= 50000000)
267fa62e10dSLinus Walleij return 5000000;
268fa62e10dSLinus Walleij /* Slam to closest 0.25 MHz */
269fa62e10dSLinus Walleij return DIV_ROUND_CLOSEST(rate, 250000) * 250000;
270fa62e10dSLinus Walleij }
271fa62e10dSLinus Walleij
272fa62e10dSLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_PCI) {
273fa62e10dSLinus Walleij /*
274fa62e10dSLinus Walleij * If we're below or less than halfway from 25 to 33 MHz
275fa62e10dSLinus Walleij * select 25 MHz
276fa62e10dSLinus Walleij */
277fa62e10dSLinus Walleij if (rate <= 25000000 || rate < 29000000)
278fa62e10dSLinus Walleij return 25000000;
279fa62e10dSLinus Walleij /* Else just return the default frequency */
280fa62e10dSLinus Walleij return 33000000;
281fa62e10dSLinus Walleij }
282fa62e10dSLinus Walleij
28391b87a47SLinus Walleij vco = icst_hz_to_vco(icst->params, rate);
28491b87a47SLinus Walleij return icst_hz(icst->params, vco);
28591b87a47SLinus Walleij }
28691b87a47SLinus Walleij
icst_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)28791b87a47SLinus Walleij static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
28891b87a47SLinus Walleij unsigned long parent_rate)
28991b87a47SLinus Walleij {
29091b87a47SLinus Walleij struct clk_icst *icst = to_icst(hw);
29191b87a47SLinus Walleij struct icst_vco vco;
29291b87a47SLinus Walleij
293fa62e10dSLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_PCI) {
294fa62e10dSLinus Walleij /* This clock is especially primitive */
295fa62e10dSLinus Walleij unsigned int val;
296fa62e10dSLinus Walleij int ret;
297fa62e10dSLinus Walleij
298fa62e10dSLinus Walleij if (rate == 25000000) {
299fa62e10dSLinus Walleij val = 0;
300fa62e10dSLinus Walleij } else if (rate == 33000000) {
301fa62e10dSLinus Walleij val = INTEGRATOR_AP_PCI_25_33_MHZ;
302fa62e10dSLinus Walleij } else {
303fa62e10dSLinus Walleij pr_err("ICST: cannot set PCI frequency %lu\n",
304fa62e10dSLinus Walleij rate);
305fa62e10dSLinus Walleij return -EINVAL;
306fa62e10dSLinus Walleij }
307fa62e10dSLinus Walleij ret = regmap_write(icst->map, icst->lockreg_off,
308fa62e10dSLinus Walleij VERSATILE_LOCK_VAL);
309fa62e10dSLinus Walleij if (ret)
310fa62e10dSLinus Walleij return ret;
311fa62e10dSLinus Walleij ret = regmap_update_bits(icst->map, icst->vcoreg_off,
312fa62e10dSLinus Walleij INTEGRATOR_AP_PCI_25_33_MHZ,
313fa62e10dSLinus Walleij val);
314fa62e10dSLinus Walleij if (ret)
315fa62e10dSLinus Walleij return ret;
316fa62e10dSLinus Walleij /* This locks the VCO again */
317fa62e10dSLinus Walleij ret = regmap_write(icst->map, icst->lockreg_off, 0);
318fa62e10dSLinus Walleij if (ret)
319fa62e10dSLinus Walleij return ret;
320fa62e10dSLinus Walleij return 0;
321fa62e10dSLinus Walleij }
322fa62e10dSLinus Walleij
323a183da63SLinus Walleij if (parent_rate)
324a183da63SLinus Walleij icst->params->ref = parent_rate;
32591b87a47SLinus Walleij vco = icst_hz_to_vco(icst->params, rate);
32691b87a47SLinus Walleij icst->rate = icst_hz(icst->params, vco);
327179c8fb3SLinus Walleij return vco_set(icst, vco);
32891b87a47SLinus Walleij }
32991b87a47SLinus Walleij
33091b87a47SLinus Walleij static const struct clk_ops icst_ops = {
33191b87a47SLinus Walleij .recalc_rate = icst_recalc_rate,
33291b87a47SLinus Walleij .round_rate = icst_round_rate,
33391b87a47SLinus Walleij .set_rate = icst_set_rate,
33491b87a47SLinus Walleij };
33591b87a47SLinus Walleij
icst_clk_setup(struct device * dev,const struct clk_icst_desc * desc,const char * name,const char * parent_name,struct regmap * map,enum icst_control_type ctype)336eb9d6428SLinus Walleij struct clk *icst_clk_setup(struct device *dev,
3377a9ad671SLinus Walleij const struct clk_icst_desc *desc,
338ae6e694eSLinus Walleij const char *name,
339bf6edb4bSLinus Walleij const char *parent_name,
3405e23c593SLinus Walleij struct regmap *map,
3415e23c593SLinus Walleij enum icst_control_type ctype)
34291b87a47SLinus Walleij {
34391b87a47SLinus Walleij struct clk *clk;
34491b87a47SLinus Walleij struct clk_icst *icst;
34591b87a47SLinus Walleij struct clk_init_data init;
346a183da63SLinus Walleij struct icst_params *pclone;
34791b87a47SLinus Walleij
348a72da43cSMarkus Elfring icst = kzalloc(sizeof(*icst), GFP_KERNEL);
349e343b81eSMarkus Elfring if (!icst)
35091b87a47SLinus Walleij return ERR_PTR(-ENOMEM);
351a183da63SLinus Walleij
352a183da63SLinus Walleij pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL);
353a183da63SLinus Walleij if (!pclone) {
354ab7ad353SColin Ian King kfree(icst);
355a183da63SLinus Walleij return ERR_PTR(-ENOMEM);
356a183da63SLinus Walleij }
357a183da63SLinus Walleij
358ae6e694eSLinus Walleij init.name = name;
35991b87a47SLinus Walleij init.ops = &icst_ops;
360ac82a8b5SStephen Boyd init.flags = 0;
361a183da63SLinus Walleij init.parent_names = (parent_name ? &parent_name : NULL);
362a183da63SLinus Walleij init.num_parents = (parent_name ? 1 : 0);
363384d977dSLinus Walleij icst->map = map;
36491b87a47SLinus Walleij icst->hw.init = &init;
365a183da63SLinus Walleij icst->params = pclone;
366179c8fb3SLinus Walleij icst->vcoreg_off = desc->vco_offset;
367179c8fb3SLinus Walleij icst->lockreg_off = desc->lock_offset;
3685e23c593SLinus Walleij icst->ctype = ctype;
36991b87a47SLinus Walleij
37091b87a47SLinus Walleij clk = clk_register(dev, &icst->hw);
3717bdccef3SLinus Walleij if (IS_ERR(clk)) {
3727bdccef3SLinus Walleij kfree(pclone);
37391b87a47SLinus Walleij kfree(icst);
3747bdccef3SLinus Walleij }
37591b87a47SLinus Walleij
37691b87a47SLinus Walleij return clk;
37791b87a47SLinus Walleij }
378eb9d6428SLinus Walleij EXPORT_SYMBOL_GPL(icst_clk_setup);
379384d977dSLinus Walleij
icst_clk_register(struct device * dev,const struct clk_icst_desc * desc,const char * name,const char * parent_name,void __iomem * base)380384d977dSLinus Walleij struct clk *icst_clk_register(struct device *dev,
381384d977dSLinus Walleij const struct clk_icst_desc *desc,
382384d977dSLinus Walleij const char *name,
383384d977dSLinus Walleij const char *parent_name,
384384d977dSLinus Walleij void __iomem *base)
385384d977dSLinus Walleij {
386384d977dSLinus Walleij struct regmap_config icst_regmap_conf = {
387384d977dSLinus Walleij .reg_bits = 32,
388384d977dSLinus Walleij .val_bits = 32,
389384d977dSLinus Walleij .reg_stride = 4,
390384d977dSLinus Walleij };
391384d977dSLinus Walleij struct regmap *map;
392384d977dSLinus Walleij
393384d977dSLinus Walleij map = regmap_init_mmio(dev, base, &icst_regmap_conf);
394384d977dSLinus Walleij if (IS_ERR(map)) {
395384d977dSLinus Walleij pr_err("could not initialize ICST regmap\n");
396384d977dSLinus Walleij return ERR_CAST(map);
397384d977dSLinus Walleij }
3985e23c593SLinus Walleij return icst_clk_setup(dev, desc, name, parent_name, map,
3995e23c593SLinus Walleij ICST_VERSATILE);
400384d977dSLinus Walleij }
401a218d7faSArnd Bergmann EXPORT_SYMBOL_GPL(icst_clk_register);
402d430819dSLinus Walleij
403d430819dSLinus Walleij #ifdef CONFIG_OF
404d430819dSLinus Walleij /*
405d430819dSLinus Walleij * In a device tree, an memory-mapped ICST clock appear as a child
406d430819dSLinus Walleij * of a syscon node. Assume this and probe it only as a child of a
407d430819dSLinus Walleij * syscon.
408d430819dSLinus Walleij */
409d430819dSLinus Walleij
410d430819dSLinus Walleij static const struct icst_params icst525_params = {
411d430819dSLinus Walleij .vco_max = ICST525_VCO_MAX_5V,
412d430819dSLinus Walleij .vco_min = ICST525_VCO_MIN,
413d430819dSLinus Walleij .vd_min = 8,
414d430819dSLinus Walleij .vd_max = 263,
415d430819dSLinus Walleij .rd_min = 3,
416d430819dSLinus Walleij .rd_max = 65,
417d430819dSLinus Walleij .s2div = icst525_s2div,
418d430819dSLinus Walleij .idx2s = icst525_idx2s,
419d430819dSLinus Walleij };
420d430819dSLinus Walleij
421d430819dSLinus Walleij static const struct icst_params icst307_params = {
422d430819dSLinus Walleij .vco_max = ICST307_VCO_MAX,
423d430819dSLinus Walleij .vco_min = ICST307_VCO_MIN,
424d430819dSLinus Walleij .vd_min = 4 + 8,
425d430819dSLinus Walleij .vd_max = 511 + 8,
426d430819dSLinus Walleij .rd_min = 1 + 2,
427d430819dSLinus Walleij .rd_max = 127 + 2,
428d430819dSLinus Walleij .s2div = icst307_s2div,
429d430819dSLinus Walleij .idx2s = icst307_idx2s,
430d430819dSLinus Walleij };
431d430819dSLinus Walleij
4320c1d46d3SLee Jones /*
4335e23c593SLinus Walleij * The core modules on the Integrator/AP and Integrator/CP have
4345e23c593SLinus Walleij * especially crippled ICST525 control.
4355e23c593SLinus Walleij */
4365e23c593SLinus Walleij static const struct icst_params icst525_apcp_cm_params = {
4375e23c593SLinus Walleij .vco_max = ICST525_VCO_MAX_5V,
4385e23c593SLinus Walleij .vco_min = ICST525_VCO_MIN,
4395e23c593SLinus Walleij /* Minimum 12 MHz, VDW = 4 */
4405e23c593SLinus Walleij .vd_min = 12,
4415e23c593SLinus Walleij /*
4425e23c593SLinus Walleij * Maximum 160 MHz, VDW = 152 for all core modules, but
4435e23c593SLinus Walleij * CM926EJ-S, CM1026EJ-S and CM1136JF-S can actually
4445e23c593SLinus Walleij * go to 200 MHz (max VDW = 192).
4455e23c593SLinus Walleij */
4465e23c593SLinus Walleij .vd_max = 192,
4475e23c593SLinus Walleij /* r is hardcoded to 22 and this is the actual divisor, +2 */
4485e23c593SLinus Walleij .rd_min = 24,
4495e23c593SLinus Walleij .rd_max = 24,
4505e23c593SLinus Walleij .s2div = icst525_s2div,
4515e23c593SLinus Walleij .idx2s = icst525_idx2s,
4525e23c593SLinus Walleij };
4535e23c593SLinus Walleij
454fa62e10dSLinus Walleij static const struct icst_params icst525_ap_sys_params = {
455fa62e10dSLinus Walleij .vco_max = ICST525_VCO_MAX_5V,
456fa62e10dSLinus Walleij .vco_min = ICST525_VCO_MIN,
457fa62e10dSLinus Walleij /* Minimum 3 MHz, VDW = 4 */
458fa62e10dSLinus Walleij .vd_min = 3,
459fa62e10dSLinus Walleij /* Maximum 50 MHz, VDW = 192 */
460fa62e10dSLinus Walleij .vd_max = 50,
461fa62e10dSLinus Walleij /* r is hardcoded to 46 and this is the actual divisor, +2 */
462fa62e10dSLinus Walleij .rd_min = 48,
463fa62e10dSLinus Walleij .rd_max = 48,
464fa62e10dSLinus Walleij .s2div = icst525_s2div,
465fa62e10dSLinus Walleij .idx2s = icst525_idx2s,
466fa62e10dSLinus Walleij };
467fa62e10dSLinus Walleij
468fa62e10dSLinus Walleij static const struct icst_params icst525_ap_pci_params = {
469fa62e10dSLinus Walleij .vco_max = ICST525_VCO_MAX_5V,
470fa62e10dSLinus Walleij .vco_min = ICST525_VCO_MIN,
471fa62e10dSLinus Walleij /* Minimum 25 MHz */
472fa62e10dSLinus Walleij .vd_min = 25,
473fa62e10dSLinus Walleij /* Maximum 33 MHz */
474fa62e10dSLinus Walleij .vd_max = 33,
475fa62e10dSLinus Walleij /* r is hardcoded to 14 or 22 and this is the actual divisors +2 */
476fa62e10dSLinus Walleij .rd_min = 16,
477fa62e10dSLinus Walleij .rd_max = 24,
478fa62e10dSLinus Walleij .s2div = icst525_s2div,
479fa62e10dSLinus Walleij .idx2s = icst525_idx2s,
480fa62e10dSLinus Walleij };
481fa62e10dSLinus Walleij
of_syscon_icst_setup(struct device_node * np)482d430819dSLinus Walleij static void __init of_syscon_icst_setup(struct device_node *np)
483d430819dSLinus Walleij {
484d430819dSLinus Walleij struct device_node *parent;
485d430819dSLinus Walleij struct regmap *map;
486d430819dSLinus Walleij struct clk_icst_desc icst_desc;
4871b2189f3SRob Herring const char *name;
488d430819dSLinus Walleij const char *parent_name;
489d430819dSLinus Walleij struct clk *regclk;
4905e23c593SLinus Walleij enum icst_control_type ctype;
491d430819dSLinus Walleij
492d430819dSLinus Walleij /* We do not release this reference, we are using it perpetually */
493d430819dSLinus Walleij parent = of_get_parent(np);
494d430819dSLinus Walleij if (!parent) {
495d430819dSLinus Walleij pr_err("no parent node for syscon ICST clock\n");
496d430819dSLinus Walleij return;
497d430819dSLinus Walleij }
498d430819dSLinus Walleij map = syscon_node_to_regmap(parent);
499d430819dSLinus Walleij if (IS_ERR(map)) {
500d430819dSLinus Walleij pr_err("no regmap for syscon ICST clock parent\n");
501d430819dSLinus Walleij return;
502d430819dSLinus Walleij }
503d430819dSLinus Walleij
50469bfe08fSRob Herring if (of_property_read_u32(np, "reg", &icst_desc.vco_offset) &&
50569bfe08fSRob Herring of_property_read_u32(np, "vco-offset", &icst_desc.vco_offset)) {
506d430819dSLinus Walleij pr_err("no VCO register offset for ICST clock\n");
507d430819dSLinus Walleij return;
508d430819dSLinus Walleij }
509d430819dSLinus Walleij if (of_property_read_u32(np, "lock-offset", &icst_desc.lock_offset)) {
510d430819dSLinus Walleij pr_err("no lock register offset for ICST clock\n");
511d430819dSLinus Walleij return;
512d430819dSLinus Walleij }
513d430819dSLinus Walleij
5145e23c593SLinus Walleij if (of_device_is_compatible(np, "arm,syscon-icst525")) {
515d430819dSLinus Walleij icst_desc.params = &icst525_params;
5165e23c593SLinus Walleij ctype = ICST_VERSATILE;
5175e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst307")) {
518d430819dSLinus Walleij icst_desc.params = &icst307_params;
5195e23c593SLinus Walleij ctype = ICST_VERSATILE;
5205e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-cm")) {
5215e23c593SLinus Walleij icst_desc.params = &icst525_apcp_cm_params;
5225e23c593SLinus Walleij ctype = ICST_INTEGRATOR_AP_CM;
523fa62e10dSLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-sys")) {
524fa62e10dSLinus Walleij icst_desc.params = &icst525_ap_sys_params;
525fa62e10dSLinus Walleij ctype = ICST_INTEGRATOR_AP_SYS;
526fa62e10dSLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-pci")) {
527fa62e10dSLinus Walleij icst_desc.params = &icst525_ap_pci_params;
528fa62e10dSLinus Walleij ctype = ICST_INTEGRATOR_AP_PCI;
5295e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-core")) {
5305e23c593SLinus Walleij icst_desc.params = &icst525_apcp_cm_params;
5315e23c593SLinus Walleij ctype = ICST_INTEGRATOR_CP_CM_CORE;
5325e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-mem")) {
5335e23c593SLinus Walleij icst_desc.params = &icst525_apcp_cm_params;
5345e23c593SLinus Walleij ctype = ICST_INTEGRATOR_CP_CM_MEM;
5355e23c593SLinus Walleij } else {
5361b2189f3SRob Herring pr_err("unknown ICST clock %pOF\n", np);
537d430819dSLinus Walleij return;
538d430819dSLinus Walleij }
539d430819dSLinus Walleij
540d430819dSLinus Walleij /* Parent clock name is not the same as node parent */
541d430819dSLinus Walleij parent_name = of_clk_get_parent_name(np, 0);
5421b2189f3SRob Herring name = kasprintf(GFP_KERNEL, "%pOFP", np);
543d430819dSLinus Walleij
5445e23c593SLinus Walleij regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map, ctype);
545d430819dSLinus Walleij if (IS_ERR(regclk)) {
546d430819dSLinus Walleij pr_err("error setting up syscon ICST clock %s\n", name);
547*2d4fcc5aSDan Carpenter kfree(name);
548d430819dSLinus Walleij return;
549d430819dSLinus Walleij }
550d430819dSLinus Walleij of_clk_add_provider(np, of_clk_src_simple_get, regclk);
551d430819dSLinus Walleij pr_debug("registered syscon ICST clock %s\n", name);
552d430819dSLinus Walleij }
553d430819dSLinus Walleij
554d430819dSLinus Walleij CLK_OF_DECLARE(arm_syscon_icst525_clk,
555d430819dSLinus Walleij "arm,syscon-icst525", of_syscon_icst_setup);
556d430819dSLinus Walleij CLK_OF_DECLARE(arm_syscon_icst307_clk,
557d430819dSLinus Walleij "arm,syscon-icst307", of_syscon_icst_setup);
5585e23c593SLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorap_cm_clk,
5595e23c593SLinus Walleij "arm,syscon-icst525-integratorap-cm", of_syscon_icst_setup);
560fa62e10dSLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorap_sys_clk,
561fa62e10dSLinus Walleij "arm,syscon-icst525-integratorap-sys", of_syscon_icst_setup);
562fa62e10dSLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorap_pci_clk,
563fa62e10dSLinus Walleij "arm,syscon-icst525-integratorap-pci", of_syscon_icst_setup);
5645e23c593SLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorcp_cm_core_clk,
5655e23c593SLinus Walleij "arm,syscon-icst525-integratorcp-cm-core", of_syscon_icst_setup);
5665e23c593SLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorcp_cm_mem_clk,
5675e23c593SLinus Walleij "arm,syscon-icst525-integratorcp-cm-mem", of_syscon_icst_setup);
568d430819dSLinus Walleij #endif
569