191b87a47SLinus Walleij /* 291b87a47SLinus Walleij * Driver for the ICST307 VCO clock found in the ARM Reference designs. 391b87a47SLinus Walleij * We wrap the custom interface from <asm/hardware/icst.h> into the generic 491b87a47SLinus Walleij * clock framework. 591b87a47SLinus Walleij * 6d430819dSLinus Walleij * Copyright (C) 2012-2015 Linus Walleij 7401301ccSLinus Walleij * 8401301ccSLinus Walleij * This program is free software; you can redistribute it and/or modify 9401301ccSLinus Walleij * it under the terms of the GNU General Public License version 2 as 10401301ccSLinus Walleij * published by the Free Software Foundation. 11401301ccSLinus Walleij * 1291b87a47SLinus Walleij * TODO: when all ARM reference designs are migrated to generic clocks, the 1391b87a47SLinus Walleij * ICST clock code from the ARM tree should probably be merged into this 1491b87a47SLinus Walleij * file. 1591b87a47SLinus Walleij */ 166d31e3b2SStephen Boyd #include <linux/kernel.h> 176d31e3b2SStephen Boyd #include <linux/slab.h> 186d31e3b2SStephen Boyd #include <linux/export.h> 1991b87a47SLinus Walleij #include <linux/err.h> 2091b87a47SLinus Walleij #include <linux/clk-provider.h> 217a9ad671SLinus Walleij #include <linux/io.h> 22179c8fb3SLinus Walleij #include <linux/regmap.h> 23384d977dSLinus Walleij #include <linux/mfd/syscon.h> 2491b87a47SLinus Walleij 2591b87a47SLinus Walleij #include "clk-icst.h" 2691b87a47SLinus Walleij 27179c8fb3SLinus Walleij /* Magic unlocking token used on all Versatile boards */ 28179c8fb3SLinus Walleij #define VERSATILE_LOCK_VAL 0xA05F 29179c8fb3SLinus Walleij 30*5e23c593SLinus Walleij #define VERSATILE_AUX_OSC_BITS 0x7FFFF 31*5e23c593SLinus Walleij #define INTEGRATOR_AP_CM_BITS 0xFF 32*5e23c593SLinus Walleij #define INTEGRATOR_CP_CM_CORE_BITS 0x7FF 33*5e23c593SLinus Walleij #define INTEGRATOR_CP_CM_MEM_BITS 0x7FF000 34*5e23c593SLinus Walleij 35*5e23c593SLinus Walleij /** 36*5e23c593SLinus Walleij * enum icst_control_type - the type of ICST control register 37*5e23c593SLinus Walleij */ 38*5e23c593SLinus Walleij enum icst_control_type { 39*5e23c593SLinus Walleij ICST_VERSATILE, /* The standard type, all control bits available */ 40*5e23c593SLinus Walleij ICST_INTEGRATOR_AP_CM, /* Only 8 bits of VDW available */ 41*5e23c593SLinus Walleij ICST_INTEGRATOR_CP_CM_CORE, /* Only 8 bits of VDW and 3 bits of OD */ 42*5e23c593SLinus Walleij ICST_INTEGRATOR_CP_CM_MEM, /* Only 8 bits of VDW and 3 bits of OD */ 43*5e23c593SLinus Walleij }; 44*5e23c593SLinus Walleij 4591b87a47SLinus Walleij /** 4691b87a47SLinus Walleij * struct clk_icst - ICST VCO clock wrapper 4791b87a47SLinus Walleij * @hw: corresponding clock hardware entry 487a9ad671SLinus Walleij * @vcoreg: VCO register address 497a9ad671SLinus Walleij * @lockreg: VCO lock register address 5091b87a47SLinus Walleij * @params: parameters for this ICST instance 5191b87a47SLinus Walleij * @rate: current rate 52*5e23c593SLinus Walleij * @ctype: the type of control register for the ICST 5391b87a47SLinus Walleij */ 5491b87a47SLinus Walleij struct clk_icst { 5591b87a47SLinus Walleij struct clk_hw hw; 56179c8fb3SLinus Walleij struct regmap *map; 57179c8fb3SLinus Walleij u32 vcoreg_off; 58179c8fb3SLinus Walleij u32 lockreg_off; 59a183da63SLinus Walleij struct icst_params *params; 6091b87a47SLinus Walleij unsigned long rate; 61*5e23c593SLinus Walleij enum icst_control_type ctype; 6291b87a47SLinus Walleij }; 6391b87a47SLinus Walleij 6491b87a47SLinus Walleij #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) 6591b87a47SLinus Walleij 667a9ad671SLinus Walleij /** 67179c8fb3SLinus Walleij * vco_get() - get ICST VCO settings from a certain ICST 68179c8fb3SLinus Walleij * @icst: the ICST clock to get 69179c8fb3SLinus Walleij * @vco: the VCO struct to return the value in 707a9ad671SLinus Walleij */ 71179c8fb3SLinus Walleij static int vco_get(struct clk_icst *icst, struct icst_vco *vco) 727a9ad671SLinus Walleij { 737a9ad671SLinus Walleij u32 val; 74179c8fb3SLinus Walleij int ret; 757a9ad671SLinus Walleij 76179c8fb3SLinus Walleij ret = regmap_read(icst->map, icst->vcoreg_off, &val); 77179c8fb3SLinus Walleij if (ret) 78179c8fb3SLinus Walleij return ret; 79*5e23c593SLinus Walleij 80*5e23c593SLinus Walleij /* 81*5e23c593SLinus Walleij * The Integrator/AP core clock can only access the low eight 82*5e23c593SLinus Walleij * bits of the v PLL divider. Bit 8 is tied low and always zero, 83*5e23c593SLinus Walleij * r is hardwired to 22 and output divider s is hardwired to 1 84*5e23c593SLinus Walleij * (divide by 2) according to the document 85*5e23c593SLinus Walleij * "Integrator CM926EJ-S, CM946E-S, CM966E-S, CM1026EJ-S and 86*5e23c593SLinus Walleij * CM1136JF-S User Guide" ARM DUI 0138E, page 3-13 thru 3-14. 87*5e23c593SLinus Walleij */ 88*5e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_CM) { 89*5e23c593SLinus Walleij vco->v = val & INTEGRATOR_AP_CM_BITS; 90*5e23c593SLinus Walleij vco->r = 22; 91*5e23c593SLinus Walleij vco->s = 1; 92*5e23c593SLinus Walleij return 0; 93*5e23c593SLinus Walleij } 94*5e23c593SLinus Walleij 95*5e23c593SLinus Walleij /* 96*5e23c593SLinus Walleij * The Integrator/CP core clock can access the low eight bits 97*5e23c593SLinus Walleij * of the v PLL divider. Bit 8 is tied low and always zero, 98*5e23c593SLinus Walleij * r is hardwired to 22 and the output divider s is accessible 99*5e23c593SLinus Walleij * in bits 8 thru 10 according to the document 100*5e23c593SLinus Walleij * "Integrator/CM940T, CM920T, CM740T, and CM720T User Guide" 101*5e23c593SLinus Walleij * ARM DUI 0157A, page 3-20 thru 3-23 and 4-10. 102*5e23c593SLinus Walleij */ 103*5e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { 104*5e23c593SLinus Walleij vco->v = val & 0xFF; 105*5e23c593SLinus Walleij vco->r = 22; 106*5e23c593SLinus Walleij vco->s = (val >> 8) & 7; 107*5e23c593SLinus Walleij return 0; 108*5e23c593SLinus Walleij } 109*5e23c593SLinus Walleij 110*5e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { 111*5e23c593SLinus Walleij vco->v = (val >> 12) & 0xFF; 112*5e23c593SLinus Walleij vco->r = 22; 113*5e23c593SLinus Walleij vco->s = (val >> 20) & 7; 114*5e23c593SLinus Walleij return 0; 115*5e23c593SLinus Walleij } 116*5e23c593SLinus Walleij 117179c8fb3SLinus Walleij vco->v = val & 0x1ff; 118179c8fb3SLinus Walleij vco->r = (val >> 9) & 0x7f; 119179c8fb3SLinus Walleij vco->s = (val >> 16) & 03; 120179c8fb3SLinus Walleij return 0; 1217a9ad671SLinus Walleij } 1227a9ad671SLinus Walleij 1237a9ad671SLinus Walleij /** 1247a9ad671SLinus Walleij * vco_set() - commit changes to an ICST VCO 125179c8fb3SLinus Walleij * @icst: the ICST clock to set 126179c8fb3SLinus Walleij * @vco: the VCO struct to set the changes from 1277a9ad671SLinus Walleij */ 128179c8fb3SLinus Walleij static int vco_set(struct clk_icst *icst, struct icst_vco vco) 1297a9ad671SLinus Walleij { 130*5e23c593SLinus Walleij u32 mask; 1317a9ad671SLinus Walleij u32 val; 132179c8fb3SLinus Walleij int ret; 1337a9ad671SLinus Walleij 134*5e23c593SLinus Walleij /* Mask the bits used by the VCO */ 135*5e23c593SLinus Walleij switch (icst->ctype) { 136*5e23c593SLinus Walleij case ICST_INTEGRATOR_AP_CM: 137*5e23c593SLinus Walleij mask = INTEGRATOR_AP_CM_BITS; 138*5e23c593SLinus Walleij val = vco.v & 0xFF; 139*5e23c593SLinus Walleij if (vco.v & 0x100) 140*5e23c593SLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n"); 141*5e23c593SLinus Walleij if (vco.s != 1) 142*5e23c593SLinus Walleij pr_err("ICST error: tried to use VOD != 1\n"); 143*5e23c593SLinus Walleij if (vco.r != 22) 144*5e23c593SLinus Walleij pr_err("ICST error: tried to use RDW != 22\n"); 145*5e23c593SLinus Walleij break; 146*5e23c593SLinus Walleij case ICST_INTEGRATOR_CP_CM_CORE: 147*5e23c593SLinus Walleij mask = INTEGRATOR_CP_CM_CORE_BITS; /* Uses 12 bits */ 148*5e23c593SLinus Walleij val = (vco.v & 0xFF) | vco.s << 8; 149*5e23c593SLinus Walleij if (vco.v & 0x100) 150*5e23c593SLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n"); 151*5e23c593SLinus Walleij if (vco.r != 22) 152*5e23c593SLinus Walleij pr_err("ICST error: tried to use RDW != 22\n"); 153*5e23c593SLinus Walleij break; 154*5e23c593SLinus Walleij case ICST_INTEGRATOR_CP_CM_MEM: 155*5e23c593SLinus Walleij mask = INTEGRATOR_CP_CM_MEM_BITS; /* Uses 12 bits */ 156*5e23c593SLinus Walleij val = ((vco.v & 0xFF) << 12) | (vco.s << 20); 157*5e23c593SLinus Walleij if (vco.v & 0x100) 158*5e23c593SLinus Walleij pr_err("ICST error: tried to set bit 8 of VDW\n"); 159*5e23c593SLinus Walleij if (vco.r != 22) 160*5e23c593SLinus Walleij pr_err("ICST error: tried to use RDW != 22\n"); 161*5e23c593SLinus Walleij break; 162*5e23c593SLinus Walleij default: 163*5e23c593SLinus Walleij /* Regular auxilary oscillator */ 164*5e23c593SLinus Walleij mask = VERSATILE_AUX_OSC_BITS; 165*5e23c593SLinus Walleij val = vco.v | (vco.r << 9) | (vco.s << 16); 166*5e23c593SLinus Walleij break; 167*5e23c593SLinus Walleij } 168df9cd564SLinus Walleij 169*5e23c593SLinus Walleij pr_debug("ICST: new val = 0x%08x\n", val); 1707a9ad671SLinus Walleij 1717a9ad671SLinus Walleij /* This magic unlocks the VCO so it can be controlled */ 172179c8fb3SLinus Walleij ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL); 173179c8fb3SLinus Walleij if (ret) 174179c8fb3SLinus Walleij return ret; 175*5e23c593SLinus Walleij ret = regmap_update_bits(icst->map, icst->vcoreg_off, mask, val); 176179c8fb3SLinus Walleij if (ret) 177179c8fb3SLinus Walleij return ret; 1787a9ad671SLinus Walleij /* This locks the VCO again */ 179179c8fb3SLinus Walleij ret = regmap_write(icst->map, icst->lockreg_off, 0); 180179c8fb3SLinus Walleij if (ret) 181179c8fb3SLinus Walleij return ret; 182179c8fb3SLinus Walleij return 0; 1837a9ad671SLinus Walleij } 1847a9ad671SLinus Walleij 18591b87a47SLinus Walleij static unsigned long icst_recalc_rate(struct clk_hw *hw, 18691b87a47SLinus Walleij unsigned long parent_rate) 18791b87a47SLinus Walleij { 18891b87a47SLinus Walleij struct clk_icst *icst = to_icst(hw); 18991b87a47SLinus Walleij struct icst_vco vco; 190179c8fb3SLinus Walleij int ret; 19191b87a47SLinus Walleij 192a183da63SLinus Walleij if (parent_rate) 193a183da63SLinus Walleij icst->params->ref = parent_rate; 194179c8fb3SLinus Walleij ret = vco_get(icst, &vco); 195179c8fb3SLinus Walleij if (ret) { 196179c8fb3SLinus Walleij pr_err("ICST: could not get VCO setting\n"); 197179c8fb3SLinus Walleij return 0; 198179c8fb3SLinus Walleij } 19991b87a47SLinus Walleij icst->rate = icst_hz(icst->params, vco); 20091b87a47SLinus Walleij return icst->rate; 20191b87a47SLinus Walleij } 20291b87a47SLinus Walleij 20391b87a47SLinus Walleij static long icst_round_rate(struct clk_hw *hw, unsigned long rate, 20491b87a47SLinus Walleij unsigned long *prate) 20591b87a47SLinus Walleij { 20691b87a47SLinus Walleij struct clk_icst *icst = to_icst(hw); 20791b87a47SLinus Walleij struct icst_vco vco; 20891b87a47SLinus Walleij 209*5e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_AP_CM || 210*5e23c593SLinus Walleij icst->ctype == ICST_INTEGRATOR_CP_CM_CORE) { 211*5e23c593SLinus Walleij if (rate <= 12000000) 212*5e23c593SLinus Walleij return 12000000; 213*5e23c593SLinus Walleij if (rate >= 160000000) 214*5e23c593SLinus Walleij return 160000000; 215*5e23c593SLinus Walleij /* Slam to closest megahertz */ 216*5e23c593SLinus Walleij return DIV_ROUND_CLOSEST(rate, 1000000) * 1000000; 217*5e23c593SLinus Walleij } 218*5e23c593SLinus Walleij 219*5e23c593SLinus Walleij if (icst->ctype == ICST_INTEGRATOR_CP_CM_MEM) { 220*5e23c593SLinus Walleij if (rate <= 6000000) 221*5e23c593SLinus Walleij return 6000000; 222*5e23c593SLinus Walleij if (rate >= 66000000) 223*5e23c593SLinus Walleij return 66000000; 224*5e23c593SLinus Walleij /* Slam to closest 0.5 megahertz */ 225*5e23c593SLinus Walleij return DIV_ROUND_CLOSEST(rate, 500000) * 500000; 226*5e23c593SLinus Walleij } 227*5e23c593SLinus Walleij 22891b87a47SLinus Walleij vco = icst_hz_to_vco(icst->params, rate); 22991b87a47SLinus Walleij return icst_hz(icst->params, vco); 23091b87a47SLinus Walleij } 23191b87a47SLinus Walleij 23291b87a47SLinus Walleij static int icst_set_rate(struct clk_hw *hw, unsigned long rate, 23391b87a47SLinus Walleij unsigned long parent_rate) 23491b87a47SLinus Walleij { 23591b87a47SLinus Walleij struct clk_icst *icst = to_icst(hw); 23691b87a47SLinus Walleij struct icst_vco vco; 23791b87a47SLinus Walleij 238a183da63SLinus Walleij if (parent_rate) 239a183da63SLinus Walleij icst->params->ref = parent_rate; 24091b87a47SLinus Walleij vco = icst_hz_to_vco(icst->params, rate); 24191b87a47SLinus Walleij icst->rate = icst_hz(icst->params, vco); 242179c8fb3SLinus Walleij return vco_set(icst, vco); 24391b87a47SLinus Walleij } 24491b87a47SLinus Walleij 24591b87a47SLinus Walleij static const struct clk_ops icst_ops = { 24691b87a47SLinus Walleij .recalc_rate = icst_recalc_rate, 24791b87a47SLinus Walleij .round_rate = icst_round_rate, 24891b87a47SLinus Walleij .set_rate = icst_set_rate, 24991b87a47SLinus Walleij }; 25091b87a47SLinus Walleij 251384d977dSLinus Walleij static struct clk *icst_clk_setup(struct device *dev, 2527a9ad671SLinus Walleij const struct clk_icst_desc *desc, 253ae6e694eSLinus Walleij const char *name, 254bf6edb4bSLinus Walleij const char *parent_name, 255*5e23c593SLinus Walleij struct regmap *map, 256*5e23c593SLinus Walleij enum icst_control_type ctype) 25791b87a47SLinus Walleij { 25891b87a47SLinus Walleij struct clk *clk; 25991b87a47SLinus Walleij struct clk_icst *icst; 26091b87a47SLinus Walleij struct clk_init_data init; 261a183da63SLinus Walleij struct icst_params *pclone; 26291b87a47SLinus Walleij 26391b87a47SLinus Walleij icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); 26491b87a47SLinus Walleij if (!icst) { 26591b87a47SLinus Walleij pr_err("could not allocate ICST clock!\n"); 26691b87a47SLinus Walleij return ERR_PTR(-ENOMEM); 26791b87a47SLinus Walleij } 268a183da63SLinus Walleij 269a183da63SLinus Walleij pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL); 270a183da63SLinus Walleij if (!pclone) { 271ab7ad353SColin Ian King kfree(icst); 272a183da63SLinus Walleij pr_err("could not clone ICST params\n"); 273a183da63SLinus Walleij return ERR_PTR(-ENOMEM); 274a183da63SLinus Walleij } 275a183da63SLinus Walleij 276ae6e694eSLinus Walleij init.name = name; 27791b87a47SLinus Walleij init.ops = &icst_ops; 278ac82a8b5SStephen Boyd init.flags = 0; 279a183da63SLinus Walleij init.parent_names = (parent_name ? &parent_name : NULL); 280a183da63SLinus Walleij init.num_parents = (parent_name ? 1 : 0); 281384d977dSLinus Walleij icst->map = map; 28291b87a47SLinus Walleij icst->hw.init = &init; 283a183da63SLinus Walleij icst->params = pclone; 284179c8fb3SLinus Walleij icst->vcoreg_off = desc->vco_offset; 285179c8fb3SLinus Walleij icst->lockreg_off = desc->lock_offset; 286*5e23c593SLinus Walleij icst->ctype = ctype; 28791b87a47SLinus Walleij 28891b87a47SLinus Walleij clk = clk_register(dev, &icst->hw); 2897bdccef3SLinus Walleij if (IS_ERR(clk)) { 2907bdccef3SLinus Walleij kfree(pclone); 29191b87a47SLinus Walleij kfree(icst); 2927bdccef3SLinus Walleij } 29391b87a47SLinus Walleij 29491b87a47SLinus Walleij return clk; 29591b87a47SLinus Walleij } 296384d977dSLinus Walleij 297384d977dSLinus Walleij struct clk *icst_clk_register(struct device *dev, 298384d977dSLinus Walleij const struct clk_icst_desc *desc, 299384d977dSLinus Walleij const char *name, 300384d977dSLinus Walleij const char *parent_name, 301384d977dSLinus Walleij void __iomem *base) 302384d977dSLinus Walleij { 303384d977dSLinus Walleij struct regmap_config icst_regmap_conf = { 304384d977dSLinus Walleij .reg_bits = 32, 305384d977dSLinus Walleij .val_bits = 32, 306384d977dSLinus Walleij .reg_stride = 4, 307384d977dSLinus Walleij }; 308384d977dSLinus Walleij struct regmap *map; 309384d977dSLinus Walleij 310384d977dSLinus Walleij map = regmap_init_mmio(dev, base, &icst_regmap_conf); 311384d977dSLinus Walleij if (IS_ERR(map)) { 312384d977dSLinus Walleij pr_err("could not initialize ICST regmap\n"); 313384d977dSLinus Walleij return ERR_CAST(map); 314384d977dSLinus Walleij } 315*5e23c593SLinus Walleij return icst_clk_setup(dev, desc, name, parent_name, map, 316*5e23c593SLinus Walleij ICST_VERSATILE); 317384d977dSLinus Walleij } 318a218d7faSArnd Bergmann EXPORT_SYMBOL_GPL(icst_clk_register); 319d430819dSLinus Walleij 320d430819dSLinus Walleij #ifdef CONFIG_OF 321d430819dSLinus Walleij /* 322d430819dSLinus Walleij * In a device tree, an memory-mapped ICST clock appear as a child 323d430819dSLinus Walleij * of a syscon node. Assume this and probe it only as a child of a 324d430819dSLinus Walleij * syscon. 325d430819dSLinus Walleij */ 326d430819dSLinus Walleij 327d430819dSLinus Walleij static const struct icst_params icst525_params = { 328d430819dSLinus Walleij .vco_max = ICST525_VCO_MAX_5V, 329d430819dSLinus Walleij .vco_min = ICST525_VCO_MIN, 330d430819dSLinus Walleij .vd_min = 8, 331d430819dSLinus Walleij .vd_max = 263, 332d430819dSLinus Walleij .rd_min = 3, 333d430819dSLinus Walleij .rd_max = 65, 334d430819dSLinus Walleij .s2div = icst525_s2div, 335d430819dSLinus Walleij .idx2s = icst525_idx2s, 336d430819dSLinus Walleij }; 337d430819dSLinus Walleij 338d430819dSLinus Walleij static const struct icst_params icst307_params = { 339d430819dSLinus Walleij .vco_max = ICST307_VCO_MAX, 340d430819dSLinus Walleij .vco_min = ICST307_VCO_MIN, 341d430819dSLinus Walleij .vd_min = 4 + 8, 342d430819dSLinus Walleij .vd_max = 511 + 8, 343d430819dSLinus Walleij .rd_min = 1 + 2, 344d430819dSLinus Walleij .rd_max = 127 + 2, 345d430819dSLinus Walleij .s2div = icst307_s2div, 346d430819dSLinus Walleij .idx2s = icst307_idx2s, 347d430819dSLinus Walleij }; 348d430819dSLinus Walleij 349*5e23c593SLinus Walleij /** 350*5e23c593SLinus Walleij * The core modules on the Integrator/AP and Integrator/CP have 351*5e23c593SLinus Walleij * especially crippled ICST525 control. 352*5e23c593SLinus Walleij */ 353*5e23c593SLinus Walleij static const struct icst_params icst525_apcp_cm_params = { 354*5e23c593SLinus Walleij .vco_max = ICST525_VCO_MAX_5V, 355*5e23c593SLinus Walleij .vco_min = ICST525_VCO_MIN, 356*5e23c593SLinus Walleij /* Minimum 12 MHz, VDW = 4 */ 357*5e23c593SLinus Walleij .vd_min = 12, 358*5e23c593SLinus Walleij /* 359*5e23c593SLinus Walleij * Maximum 160 MHz, VDW = 152 for all core modules, but 360*5e23c593SLinus Walleij * CM926EJ-S, CM1026EJ-S and CM1136JF-S can actually 361*5e23c593SLinus Walleij * go to 200 MHz (max VDW = 192). 362*5e23c593SLinus Walleij */ 363*5e23c593SLinus Walleij .vd_max = 192, 364*5e23c593SLinus Walleij /* r is hardcoded to 22 and this is the actual divisor, +2 */ 365*5e23c593SLinus Walleij .rd_min = 24, 366*5e23c593SLinus Walleij .rd_max = 24, 367*5e23c593SLinus Walleij .s2div = icst525_s2div, 368*5e23c593SLinus Walleij .idx2s = icst525_idx2s, 369*5e23c593SLinus Walleij }; 370*5e23c593SLinus Walleij 371d430819dSLinus Walleij static void __init of_syscon_icst_setup(struct device_node *np) 372d430819dSLinus Walleij { 373d430819dSLinus Walleij struct device_node *parent; 374d430819dSLinus Walleij struct regmap *map; 375d430819dSLinus Walleij struct clk_icst_desc icst_desc; 376d430819dSLinus Walleij const char *name = np->name; 377d430819dSLinus Walleij const char *parent_name; 378d430819dSLinus Walleij struct clk *regclk; 379*5e23c593SLinus Walleij enum icst_control_type ctype; 380d430819dSLinus Walleij 381d430819dSLinus Walleij /* We do not release this reference, we are using it perpetually */ 382d430819dSLinus Walleij parent = of_get_parent(np); 383d430819dSLinus Walleij if (!parent) { 384d430819dSLinus Walleij pr_err("no parent node for syscon ICST clock\n"); 385d430819dSLinus Walleij return; 386d430819dSLinus Walleij } 387d430819dSLinus Walleij map = syscon_node_to_regmap(parent); 388d430819dSLinus Walleij if (IS_ERR(map)) { 389d430819dSLinus Walleij pr_err("no regmap for syscon ICST clock parent\n"); 390d430819dSLinus Walleij return; 391d430819dSLinus Walleij } 392d430819dSLinus Walleij 393d430819dSLinus Walleij if (of_property_read_u32(np, "vco-offset", &icst_desc.vco_offset)) { 394d430819dSLinus Walleij pr_err("no VCO register offset for ICST clock\n"); 395d430819dSLinus Walleij return; 396d430819dSLinus Walleij } 397d430819dSLinus Walleij if (of_property_read_u32(np, "lock-offset", &icst_desc.lock_offset)) { 398d430819dSLinus Walleij pr_err("no lock register offset for ICST clock\n"); 399d430819dSLinus Walleij return; 400d430819dSLinus Walleij } 401d430819dSLinus Walleij 402*5e23c593SLinus Walleij if (of_device_is_compatible(np, "arm,syscon-icst525")) { 403d430819dSLinus Walleij icst_desc.params = &icst525_params; 404*5e23c593SLinus Walleij ctype = ICST_VERSATILE; 405*5e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst307")) { 406d430819dSLinus Walleij icst_desc.params = &icst307_params; 407*5e23c593SLinus Walleij ctype = ICST_VERSATILE; 408*5e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorap-cm")) { 409*5e23c593SLinus Walleij icst_desc.params = &icst525_apcp_cm_params; 410*5e23c593SLinus Walleij ctype = ICST_INTEGRATOR_AP_CM; 411*5e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-core")) { 412*5e23c593SLinus Walleij icst_desc.params = &icst525_apcp_cm_params; 413*5e23c593SLinus Walleij ctype = ICST_INTEGRATOR_CP_CM_CORE; 414*5e23c593SLinus Walleij } else if (of_device_is_compatible(np, "arm,syscon-icst525-integratorcp-cm-mem")) { 415*5e23c593SLinus Walleij icst_desc.params = &icst525_apcp_cm_params; 416*5e23c593SLinus Walleij ctype = ICST_INTEGRATOR_CP_CM_MEM; 417*5e23c593SLinus Walleij } else { 418d430819dSLinus Walleij pr_err("unknown ICST clock %s\n", name); 419d430819dSLinus Walleij return; 420d430819dSLinus Walleij } 421d430819dSLinus Walleij 422d430819dSLinus Walleij /* Parent clock name is not the same as node parent */ 423d430819dSLinus Walleij parent_name = of_clk_get_parent_name(np, 0); 424d430819dSLinus Walleij 425*5e23c593SLinus Walleij regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map, ctype); 426d430819dSLinus Walleij if (IS_ERR(regclk)) { 427d430819dSLinus Walleij pr_err("error setting up syscon ICST clock %s\n", name); 428d430819dSLinus Walleij return; 429d430819dSLinus Walleij } 430d430819dSLinus Walleij of_clk_add_provider(np, of_clk_src_simple_get, regclk); 431d430819dSLinus Walleij pr_debug("registered syscon ICST clock %s\n", name); 432d430819dSLinus Walleij } 433d430819dSLinus Walleij 434d430819dSLinus Walleij CLK_OF_DECLARE(arm_syscon_icst525_clk, 435d430819dSLinus Walleij "arm,syscon-icst525", of_syscon_icst_setup); 436d430819dSLinus Walleij CLK_OF_DECLARE(arm_syscon_icst307_clk, 437d430819dSLinus Walleij "arm,syscon-icst307", of_syscon_icst_setup); 438*5e23c593SLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorap_cm_clk, 439*5e23c593SLinus Walleij "arm,syscon-icst525-integratorap-cm", of_syscon_icst_setup); 440*5e23c593SLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorcp_cm_core_clk, 441*5e23c593SLinus Walleij "arm,syscon-icst525-integratorcp-cm-core", of_syscon_icst_setup); 442*5e23c593SLinus Walleij CLK_OF_DECLARE(arm_syscon_integratorcp_cm_mem_clk, 443*5e23c593SLinus Walleij "arm,syscon-icst525-integratorcp-cm-mem", of_syscon_icst_setup); 444d430819dSLinus Walleij #endif 445