13a580e9eSGhennadi Procopciuc /* 23a580e9eSGhennadi Procopciuc * Copyright 2024 NXP 33a580e9eSGhennadi Procopciuc * 43a580e9eSGhennadi Procopciuc * SPDX-License-Identifier: BSD-3-Clause 53a580e9eSGhennadi Procopciuc */ 63a580e9eSGhennadi Procopciuc #include <errno.h> 73a580e9eSGhennadi Procopciuc 88ab34357SGhennadi Procopciuc #include <s32cc-clk-regs.h> 98ab34357SGhennadi Procopciuc 10d9373519SGhennadi Procopciuc #include <common/debug.h> 113a580e9eSGhennadi Procopciuc #include <drivers/clk.h> 128ab34357SGhennadi Procopciuc #include <lib/mmio.h> 13d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h> 14d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h> 15d9373519SGhennadi Procopciuc 16d9373519SGhennadi Procopciuc #define MAX_STACK_DEPTH (15U) 17d9373519SGhennadi Procopciuc 188ab34357SGhennadi Procopciuc struct s32cc_clk_drv { 198ab34357SGhennadi Procopciuc uintptr_t fxosc_base; 208ab34357SGhennadi Procopciuc }; 218ab34357SGhennadi Procopciuc 22d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth) 23d9373519SGhennadi Procopciuc { 24d9373519SGhennadi Procopciuc if (*depth == 0U) { 25d9373519SGhennadi Procopciuc return -ENOMEM; 26d9373519SGhennadi Procopciuc } 27d9373519SGhennadi Procopciuc 28d9373519SGhennadi Procopciuc (*depth)--; 29d9373519SGhennadi Procopciuc return 0; 30d9373519SGhennadi Procopciuc } 313a580e9eSGhennadi Procopciuc 328ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void) 338ab34357SGhennadi Procopciuc { 348ab34357SGhennadi Procopciuc static struct s32cc_clk_drv driver = { 358ab34357SGhennadi Procopciuc .fxosc_base = FXOSC_BASE_ADDR, 368ab34357SGhennadi Procopciuc }; 378ab34357SGhennadi Procopciuc 388ab34357SGhennadi Procopciuc return &driver; 398ab34357SGhennadi Procopciuc } 408ab34357SGhennadi Procopciuc 418ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth); 428ab34357SGhennadi Procopciuc 438ab34357SGhennadi Procopciuc static int enable_clk_module(const struct s32cc_clk_obj *module, 448ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 458ab34357SGhennadi Procopciuc unsigned int *depth) 468ab34357SGhennadi Procopciuc { 478ab34357SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 488ab34357SGhennadi Procopciuc int ret; 498ab34357SGhennadi Procopciuc 508ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 518ab34357SGhennadi Procopciuc if (ret != 0) { 528ab34357SGhennadi Procopciuc return ret; 538ab34357SGhennadi Procopciuc } 548ab34357SGhennadi Procopciuc 558ab34357SGhennadi Procopciuc if (clk == NULL) { 568ab34357SGhennadi Procopciuc return -EINVAL; 578ab34357SGhennadi Procopciuc } 588ab34357SGhennadi Procopciuc 598ab34357SGhennadi Procopciuc if (clk->module != NULL) { 608ab34357SGhennadi Procopciuc return enable_module(clk->module, depth); 618ab34357SGhennadi Procopciuc } 628ab34357SGhennadi Procopciuc 638ab34357SGhennadi Procopciuc if (clk->pclock != NULL) { 648ab34357SGhennadi Procopciuc return enable_clk_module(&clk->pclock->desc, drv, depth); 658ab34357SGhennadi Procopciuc } 668ab34357SGhennadi Procopciuc 678ab34357SGhennadi Procopciuc return -EINVAL; 688ab34357SGhennadi Procopciuc } 698ab34357SGhennadi Procopciuc 708ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv) 718ab34357SGhennadi Procopciuc { 728ab34357SGhennadi Procopciuc uintptr_t fxosc_base = drv->fxosc_base; 738ab34357SGhennadi Procopciuc uint32_t ctrl; 748ab34357SGhennadi Procopciuc 758ab34357SGhennadi Procopciuc ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base)); 768ab34357SGhennadi Procopciuc if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) { 778ab34357SGhennadi Procopciuc return; 788ab34357SGhennadi Procopciuc } 798ab34357SGhennadi Procopciuc 808ab34357SGhennadi Procopciuc ctrl = FXOSC_CTRL_COMP_EN; 818ab34357SGhennadi Procopciuc ctrl &= ~FXOSC_CTRL_OSC_BYP; 828ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_EOCV(0x1); 838ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_GM_SEL(0x7); 848ab34357SGhennadi Procopciuc mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl); 858ab34357SGhennadi Procopciuc 868ab34357SGhennadi Procopciuc /* Switch ON the crystal oscillator. */ 878ab34357SGhennadi Procopciuc mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON); 888ab34357SGhennadi Procopciuc 898ab34357SGhennadi Procopciuc /* Wait until the clock is stable. */ 908ab34357SGhennadi Procopciuc while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) { 918ab34357SGhennadi Procopciuc } 928ab34357SGhennadi Procopciuc } 938ab34357SGhennadi Procopciuc 948ab34357SGhennadi Procopciuc static int enable_osc(const struct s32cc_clk_obj *module, 958ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 968ab34357SGhennadi Procopciuc unsigned int *depth) 978ab34357SGhennadi Procopciuc { 988ab34357SGhennadi Procopciuc const struct s32cc_osc *osc = s32cc_obj2osc(module); 998ab34357SGhennadi Procopciuc int ret = 0; 1008ab34357SGhennadi Procopciuc 1018ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1028ab34357SGhennadi Procopciuc if (ret != 0) { 1038ab34357SGhennadi Procopciuc return ret; 1048ab34357SGhennadi Procopciuc } 1058ab34357SGhennadi Procopciuc 1068ab34357SGhennadi Procopciuc switch (osc->source) { 1078ab34357SGhennadi Procopciuc case S32CC_FXOSC: 1088ab34357SGhennadi Procopciuc enable_fxosc(drv); 1098ab34357SGhennadi Procopciuc break; 1108ab34357SGhennadi Procopciuc /* FIRC and SIRC oscillators are enabled by default */ 1118ab34357SGhennadi Procopciuc case S32CC_FIRC: 1128ab34357SGhennadi Procopciuc break; 1138ab34357SGhennadi Procopciuc case S32CC_SIRC: 1148ab34357SGhennadi Procopciuc break; 1158ab34357SGhennadi Procopciuc default: 1168ab34357SGhennadi Procopciuc ERROR("Invalid oscillator %d\n", osc->source); 1178ab34357SGhennadi Procopciuc ret = -EINVAL; 1188ab34357SGhennadi Procopciuc break; 1198ab34357SGhennadi Procopciuc }; 1208ab34357SGhennadi Procopciuc 1218ab34357SGhennadi Procopciuc return ret; 1228ab34357SGhennadi Procopciuc } 1238ab34357SGhennadi Procopciuc 1248ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth) 1258ab34357SGhennadi Procopciuc { 1268ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv = get_drv(); 1278ab34357SGhennadi Procopciuc int ret = 0; 1288ab34357SGhennadi Procopciuc 1298ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1308ab34357SGhennadi Procopciuc if (ret != 0) { 1318ab34357SGhennadi Procopciuc return ret; 1328ab34357SGhennadi Procopciuc } 1338ab34357SGhennadi Procopciuc 1348ab34357SGhennadi Procopciuc if (drv == NULL) { 1358ab34357SGhennadi Procopciuc return -EINVAL; 1368ab34357SGhennadi Procopciuc } 1378ab34357SGhennadi Procopciuc 1388ab34357SGhennadi Procopciuc switch (module->type) { 1398ab34357SGhennadi Procopciuc case s32cc_osc_t: 1408ab34357SGhennadi Procopciuc ret = enable_osc(module, drv, depth); 1418ab34357SGhennadi Procopciuc break; 1428ab34357SGhennadi Procopciuc case s32cc_clk_t: 1438ab34357SGhennadi Procopciuc ret = enable_clk_module(module, drv, depth); 1448ab34357SGhennadi Procopciuc break; 145a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 146a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 147a8be748aSGhennadi Procopciuc break; 1483fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 1493fa91a94SGhennadi Procopciuc ret = -ENOTSUP; 1503fa91a94SGhennadi Procopciuc break; 151a8be748aSGhennadi Procopciuc case s32cc_pll_t: 152a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 153a8be748aSGhennadi Procopciuc break; 154a8be748aSGhennadi Procopciuc case s32cc_pll_out_div_t: 15544e2130aSGhennadi Procopciuc case s32cc_fixed_div_t: 156a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 157a8be748aSGhennadi Procopciuc break; 1588ab34357SGhennadi Procopciuc default: 1598ab34357SGhennadi Procopciuc ret = -EINVAL; 1608ab34357SGhennadi Procopciuc break; 1618ab34357SGhennadi Procopciuc } 1628ab34357SGhennadi Procopciuc 1638ab34357SGhennadi Procopciuc return ret; 1648ab34357SGhennadi Procopciuc } 1658ab34357SGhennadi Procopciuc 1663a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id) 1673a580e9eSGhennadi Procopciuc { 1688ab34357SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 1698ab34357SGhennadi Procopciuc const struct s32cc_clk *clk; 1708ab34357SGhennadi Procopciuc 1718ab34357SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 1728ab34357SGhennadi Procopciuc if (clk == NULL) { 1738ab34357SGhennadi Procopciuc return -EINVAL; 1748ab34357SGhennadi Procopciuc } 1758ab34357SGhennadi Procopciuc 1768ab34357SGhennadi Procopciuc return enable_module(&clk->desc, &depth); 1773a580e9eSGhennadi Procopciuc } 1783a580e9eSGhennadi Procopciuc 1793a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id) 1803a580e9eSGhennadi Procopciuc { 1813a580e9eSGhennadi Procopciuc } 1823a580e9eSGhennadi Procopciuc 1833a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id) 1843a580e9eSGhennadi Procopciuc { 1853a580e9eSGhennadi Procopciuc return false; 1863a580e9eSGhennadi Procopciuc } 1873a580e9eSGhennadi Procopciuc 1883a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id) 1893a580e9eSGhennadi Procopciuc { 1903a580e9eSGhennadi Procopciuc return 0; 1913a580e9eSGhennadi Procopciuc } 1923a580e9eSGhennadi Procopciuc 193d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 194d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 195d9373519SGhennadi Procopciuc unsigned int *depth); 196d9373519SGhennadi Procopciuc 197d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate, 198d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 199d9373519SGhennadi Procopciuc { 200d9373519SGhennadi Procopciuc struct s32cc_osc *osc = s32cc_obj2osc(module); 201d9373519SGhennadi Procopciuc int ret; 202d9373519SGhennadi Procopciuc 203d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 204d9373519SGhennadi Procopciuc if (ret != 0) { 205d9373519SGhennadi Procopciuc return ret; 206d9373519SGhennadi Procopciuc } 207d9373519SGhennadi Procopciuc 208d9373519SGhennadi Procopciuc if ((osc->freq != 0UL) && (rate != osc->freq)) { 209d9373519SGhennadi Procopciuc ERROR("Already initialized oscillator. freq = %lu\n", 210d9373519SGhennadi Procopciuc osc->freq); 211d9373519SGhennadi Procopciuc return -EINVAL; 212d9373519SGhennadi Procopciuc } 213d9373519SGhennadi Procopciuc 214d9373519SGhennadi Procopciuc osc->freq = rate; 215d9373519SGhennadi Procopciuc *orate = osc->freq; 216d9373519SGhennadi Procopciuc 217d9373519SGhennadi Procopciuc return 0; 218d9373519SGhennadi Procopciuc } 219d9373519SGhennadi Procopciuc 220d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate, 221d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 222d9373519SGhennadi Procopciuc { 223d9373519SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 224d9373519SGhennadi Procopciuc int ret; 225d9373519SGhennadi Procopciuc 226d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 227d9373519SGhennadi Procopciuc if (ret != 0) { 228d9373519SGhennadi Procopciuc return ret; 229d9373519SGhennadi Procopciuc } 230d9373519SGhennadi Procopciuc 231d9373519SGhennadi Procopciuc if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) && 232d9373519SGhennadi Procopciuc ((rate < clk->min_freq) || (rate > clk->max_freq))) { 233d9373519SGhennadi Procopciuc ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n", 234d9373519SGhennadi Procopciuc rate, clk->min_freq, clk->max_freq); 235d9373519SGhennadi Procopciuc return -EINVAL; 236d9373519SGhennadi Procopciuc } 237d9373519SGhennadi Procopciuc 238d9373519SGhennadi Procopciuc if (clk->module != NULL) { 239d9373519SGhennadi Procopciuc return set_module_rate(clk->module, rate, orate, depth); 240d9373519SGhennadi Procopciuc } 241d9373519SGhennadi Procopciuc 242d9373519SGhennadi Procopciuc if (clk->pclock != NULL) { 243d9373519SGhennadi Procopciuc return set_clk_freq(&clk->pclock->desc, rate, orate, depth); 244d9373519SGhennadi Procopciuc } 245d9373519SGhennadi Procopciuc 246d9373519SGhennadi Procopciuc return -EINVAL; 247d9373519SGhennadi Procopciuc } 248d9373519SGhennadi Procopciuc 2497ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate, 2507ad4e231SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 2517ad4e231SGhennadi Procopciuc { 2527ad4e231SGhennadi Procopciuc struct s32cc_pll *pll = s32cc_obj2pll(module); 2537ad4e231SGhennadi Procopciuc int ret; 2547ad4e231SGhennadi Procopciuc 2557ad4e231SGhennadi Procopciuc ret = update_stack_depth(depth); 2567ad4e231SGhennadi Procopciuc if (ret != 0) { 2577ad4e231SGhennadi Procopciuc return ret; 2587ad4e231SGhennadi Procopciuc } 2597ad4e231SGhennadi Procopciuc 2607ad4e231SGhennadi Procopciuc if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) { 2617ad4e231SGhennadi Procopciuc ERROR("PLL frequency was already set\n"); 2627ad4e231SGhennadi Procopciuc return -EINVAL; 2637ad4e231SGhennadi Procopciuc } 2647ad4e231SGhennadi Procopciuc 2657ad4e231SGhennadi Procopciuc pll->vco_freq = rate; 2667ad4e231SGhennadi Procopciuc *orate = pll->vco_freq; 2677ad4e231SGhennadi Procopciuc 2687ad4e231SGhennadi Procopciuc return 0; 2697ad4e231SGhennadi Procopciuc } 2707ad4e231SGhennadi Procopciuc 271de950ef0SGhennadi Procopciuc static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 272de950ef0SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 273de950ef0SGhennadi Procopciuc { 274de950ef0SGhennadi Procopciuc struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 275de950ef0SGhennadi Procopciuc const struct s32cc_pll *pll; 276de950ef0SGhennadi Procopciuc unsigned long prate, dc; 277de950ef0SGhennadi Procopciuc int ret; 278de950ef0SGhennadi Procopciuc 279de950ef0SGhennadi Procopciuc ret = update_stack_depth(depth); 280de950ef0SGhennadi Procopciuc if (ret != 0) { 281de950ef0SGhennadi Procopciuc return ret; 282de950ef0SGhennadi Procopciuc } 283de950ef0SGhennadi Procopciuc 284de950ef0SGhennadi Procopciuc if (pdiv->parent == NULL) { 285de950ef0SGhennadi Procopciuc ERROR("Failed to identify PLL divider's parent\n"); 286de950ef0SGhennadi Procopciuc return -EINVAL; 287de950ef0SGhennadi Procopciuc } 288de950ef0SGhennadi Procopciuc 289de950ef0SGhennadi Procopciuc pll = s32cc_obj2pll(pdiv->parent); 290de950ef0SGhennadi Procopciuc if (pll == NULL) { 291de950ef0SGhennadi Procopciuc ERROR("The parent of the PLL DIV is invalid\n"); 292de950ef0SGhennadi Procopciuc return -EINVAL; 293de950ef0SGhennadi Procopciuc } 294de950ef0SGhennadi Procopciuc 295de950ef0SGhennadi Procopciuc prate = pll->vco_freq; 296de950ef0SGhennadi Procopciuc 297de950ef0SGhennadi Procopciuc /** 298de950ef0SGhennadi Procopciuc * The PLL is not initialized yet, so let's take a risk 299de950ef0SGhennadi Procopciuc * and accept the proposed rate. 300de950ef0SGhennadi Procopciuc */ 301de950ef0SGhennadi Procopciuc if (prate == 0UL) { 302de950ef0SGhennadi Procopciuc pdiv->freq = rate; 303de950ef0SGhennadi Procopciuc *orate = rate; 304de950ef0SGhennadi Procopciuc return 0; 305de950ef0SGhennadi Procopciuc } 306de950ef0SGhennadi Procopciuc 307de950ef0SGhennadi Procopciuc /* Decline in case the rate cannot fit PLL's requirements. */ 308de950ef0SGhennadi Procopciuc dc = prate / rate; 309de950ef0SGhennadi Procopciuc if ((prate / dc) != rate) { 310de950ef0SGhennadi Procopciuc return -EINVAL; 311de950ef0SGhennadi Procopciuc } 312de950ef0SGhennadi Procopciuc 313de950ef0SGhennadi Procopciuc pdiv->freq = rate; 314de950ef0SGhennadi Procopciuc *orate = pdiv->freq; 315de950ef0SGhennadi Procopciuc 316de950ef0SGhennadi Procopciuc return 0; 317de950ef0SGhennadi Procopciuc } 318de950ef0SGhennadi Procopciuc 31965739db2SGhennadi Procopciuc static int set_fixed_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 32065739db2SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 32165739db2SGhennadi Procopciuc { 32265739db2SGhennadi Procopciuc const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module); 32365739db2SGhennadi Procopciuc int ret; 32465739db2SGhennadi Procopciuc 32565739db2SGhennadi Procopciuc ret = update_stack_depth(depth); 32665739db2SGhennadi Procopciuc if (ret != 0) { 32765739db2SGhennadi Procopciuc return ret; 32865739db2SGhennadi Procopciuc } 32965739db2SGhennadi Procopciuc 33065739db2SGhennadi Procopciuc if (fdiv->parent == NULL) { 33165739db2SGhennadi Procopciuc ERROR("The divider doesn't have a valid parent\b"); 33265739db2SGhennadi Procopciuc return -EINVAL; 33365739db2SGhennadi Procopciuc } 33465739db2SGhennadi Procopciuc 33565739db2SGhennadi Procopciuc ret = set_module_rate(fdiv->parent, rate * fdiv->rate_div, orate, depth); 33665739db2SGhennadi Procopciuc 33765739db2SGhennadi Procopciuc /* Update the output rate based on the parent's rate */ 33865739db2SGhennadi Procopciuc *orate /= fdiv->rate_div; 33965739db2SGhennadi Procopciuc 34065739db2SGhennadi Procopciuc return ret; 34165739db2SGhennadi Procopciuc } 34265739db2SGhennadi Procopciuc 343*64e0c226SGhennadi Procopciuc static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate, 344*64e0c226SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 345*64e0c226SGhennadi Procopciuc { 346*64e0c226SGhennadi Procopciuc const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); 347*64e0c226SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id); 348*64e0c226SGhennadi Procopciuc int ret; 349*64e0c226SGhennadi Procopciuc 350*64e0c226SGhennadi Procopciuc ret = update_stack_depth(depth); 351*64e0c226SGhennadi Procopciuc if (ret != 0) { 352*64e0c226SGhennadi Procopciuc return ret; 353*64e0c226SGhennadi Procopciuc } 354*64e0c226SGhennadi Procopciuc 355*64e0c226SGhennadi Procopciuc if (clk == NULL) { 356*64e0c226SGhennadi Procopciuc ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n", 357*64e0c226SGhennadi Procopciuc mux->index, mux->source_id); 358*64e0c226SGhennadi Procopciuc return -EINVAL; 359*64e0c226SGhennadi Procopciuc } 360*64e0c226SGhennadi Procopciuc 361*64e0c226SGhennadi Procopciuc return set_module_rate(&clk->desc, rate, orate, depth); 362*64e0c226SGhennadi Procopciuc } 363*64e0c226SGhennadi Procopciuc 364d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 365d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 366d9373519SGhennadi Procopciuc unsigned int *depth) 367d9373519SGhennadi Procopciuc { 368d9373519SGhennadi Procopciuc int ret = 0; 369d9373519SGhennadi Procopciuc 370d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 371d9373519SGhennadi Procopciuc if (ret != 0) { 372d9373519SGhennadi Procopciuc return ret; 373d9373519SGhennadi Procopciuc } 374d9373519SGhennadi Procopciuc 375d9373519SGhennadi Procopciuc switch (module->type) { 376d9373519SGhennadi Procopciuc case s32cc_clk_t: 377d9373519SGhennadi Procopciuc ret = set_clk_freq(module, rate, orate, depth); 378d9373519SGhennadi Procopciuc break; 379d9373519SGhennadi Procopciuc case s32cc_osc_t: 380d9373519SGhennadi Procopciuc ret = set_osc_freq(module, rate, orate, depth); 381d9373519SGhennadi Procopciuc break; 3827ad4e231SGhennadi Procopciuc case s32cc_pll_t: 3837ad4e231SGhennadi Procopciuc ret = set_pll_freq(module, rate, orate, depth); 3847ad4e231SGhennadi Procopciuc break; 385de950ef0SGhennadi Procopciuc case s32cc_pll_out_div_t: 386de950ef0SGhennadi Procopciuc ret = set_pll_div_freq(module, rate, orate, depth); 387de950ef0SGhennadi Procopciuc break; 38865739db2SGhennadi Procopciuc case s32cc_fixed_div_t: 38965739db2SGhennadi Procopciuc ret = set_fixed_div_freq(module, rate, orate, depth); 39065739db2SGhennadi Procopciuc break; 391a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 392*64e0c226SGhennadi Procopciuc ret = set_mux_freq(module, rate, orate, depth); 393*64e0c226SGhennadi Procopciuc break; 3943fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 395*64e0c226SGhennadi Procopciuc ret = set_mux_freq(module, rate, orate, depth); 396a8be748aSGhennadi Procopciuc break; 397d9373519SGhennadi Procopciuc default: 398d9373519SGhennadi Procopciuc ret = -EINVAL; 399d9373519SGhennadi Procopciuc break; 400d9373519SGhennadi Procopciuc } 401d9373519SGhennadi Procopciuc 402d9373519SGhennadi Procopciuc return ret; 403d9373519SGhennadi Procopciuc } 404d9373519SGhennadi Procopciuc 4053a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate, 4063a580e9eSGhennadi Procopciuc unsigned long *orate) 4073a580e9eSGhennadi Procopciuc { 408d9373519SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 409d9373519SGhennadi Procopciuc const struct s32cc_clk *clk; 410d9373519SGhennadi Procopciuc int ret; 411d9373519SGhennadi Procopciuc 412d9373519SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 413d9373519SGhennadi Procopciuc if (clk == NULL) { 414d9373519SGhennadi Procopciuc return -EINVAL; 415d9373519SGhennadi Procopciuc } 416d9373519SGhennadi Procopciuc 417d9373519SGhennadi Procopciuc ret = set_module_rate(&clk->desc, rate, orate, &depth); 418d9373519SGhennadi Procopciuc if (ret != 0) { 419d9373519SGhennadi Procopciuc ERROR("Failed to set frequency (%lu MHz) for clock %lu\n", 420d9373519SGhennadi Procopciuc rate, id); 421d9373519SGhennadi Procopciuc } 422d9373519SGhennadi Procopciuc 423d9373519SGhennadi Procopciuc return ret; 4243a580e9eSGhennadi Procopciuc } 4253a580e9eSGhennadi Procopciuc 4263a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id) 4273a580e9eSGhennadi Procopciuc { 4283a580e9eSGhennadi Procopciuc return -ENOTSUP; 4293a580e9eSGhennadi Procopciuc } 4303a580e9eSGhennadi Procopciuc 4313a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id) 4323a580e9eSGhennadi Procopciuc { 43312e7a2cdSGhennadi Procopciuc const struct s32cc_clk *parent; 43412e7a2cdSGhennadi Procopciuc const struct s32cc_clk *clk; 43512e7a2cdSGhennadi Procopciuc bool valid_source = false; 43612e7a2cdSGhennadi Procopciuc struct s32cc_clkmux *mux; 43712e7a2cdSGhennadi Procopciuc uint8_t i; 43812e7a2cdSGhennadi Procopciuc 43912e7a2cdSGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 44012e7a2cdSGhennadi Procopciuc if (clk == NULL) { 44112e7a2cdSGhennadi Procopciuc return -EINVAL; 44212e7a2cdSGhennadi Procopciuc } 44312e7a2cdSGhennadi Procopciuc 44412e7a2cdSGhennadi Procopciuc parent = s32cc_get_arch_clk(parent_id); 44512e7a2cdSGhennadi Procopciuc if (parent == NULL) { 44612e7a2cdSGhennadi Procopciuc return -EINVAL; 44712e7a2cdSGhennadi Procopciuc } 44812e7a2cdSGhennadi Procopciuc 44912e7a2cdSGhennadi Procopciuc if (!is_s32cc_clk_mux(clk)) { 45012e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a mux\n", id); 45112e7a2cdSGhennadi Procopciuc return -EINVAL; 45212e7a2cdSGhennadi Procopciuc } 45312e7a2cdSGhennadi Procopciuc 45412e7a2cdSGhennadi Procopciuc mux = s32cc_clk2mux(clk); 45512e7a2cdSGhennadi Procopciuc if (mux == NULL) { 45612e7a2cdSGhennadi Procopciuc ERROR("Failed to cast clock %lu to clock mux\n", id); 45712e7a2cdSGhennadi Procopciuc return -EINVAL; 45812e7a2cdSGhennadi Procopciuc } 45912e7a2cdSGhennadi Procopciuc 46012e7a2cdSGhennadi Procopciuc for (i = 0; i < mux->nclks; i++) { 46112e7a2cdSGhennadi Procopciuc if (mux->clkids[i] == parent_id) { 46212e7a2cdSGhennadi Procopciuc valid_source = true; 46312e7a2cdSGhennadi Procopciuc break; 46412e7a2cdSGhennadi Procopciuc } 46512e7a2cdSGhennadi Procopciuc } 46612e7a2cdSGhennadi Procopciuc 46712e7a2cdSGhennadi Procopciuc if (!valid_source) { 46812e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a valid clock for mux %lu\n", 46912e7a2cdSGhennadi Procopciuc parent_id, id); 47012e7a2cdSGhennadi Procopciuc return -EINVAL; 47112e7a2cdSGhennadi Procopciuc } 47212e7a2cdSGhennadi Procopciuc 47312e7a2cdSGhennadi Procopciuc mux->source_id = parent_id; 47412e7a2cdSGhennadi Procopciuc 47512e7a2cdSGhennadi Procopciuc return 0; 4763a580e9eSGhennadi Procopciuc } 4773a580e9eSGhennadi Procopciuc 4783a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void) 4793a580e9eSGhennadi Procopciuc { 4803a580e9eSGhennadi Procopciuc static const struct clk_ops s32cc_clk_ops = { 4813a580e9eSGhennadi Procopciuc .enable = s32cc_clk_enable, 4823a580e9eSGhennadi Procopciuc .disable = s32cc_clk_disable, 4833a580e9eSGhennadi Procopciuc .is_enabled = s32cc_clk_is_enabled, 4843a580e9eSGhennadi Procopciuc .get_rate = s32cc_clk_get_rate, 4853a580e9eSGhennadi Procopciuc .set_rate = s32cc_clk_set_rate, 4863a580e9eSGhennadi Procopciuc .get_parent = s32cc_clk_get_parent, 4873a580e9eSGhennadi Procopciuc .set_parent = s32cc_clk_set_parent, 4883a580e9eSGhennadi Procopciuc }; 4893a580e9eSGhennadi Procopciuc 4903a580e9eSGhennadi Procopciuc clk_register(&s32cc_clk_ops); 4913a580e9eSGhennadi Procopciuc } 4923a580e9eSGhennadi Procopciuc 493