xref: /linux/drivers/clk/versatile/clk-icst.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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