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> 13b5101c45SGhennadi Procopciuc #include <s32cc-clk-ids.h> 14d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h> 15d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h> 16d9373519SGhennadi Procopciuc 17d9373519SGhennadi Procopciuc #define MAX_STACK_DEPTH (15U) 18d9373519SGhennadi Procopciuc 19b5101c45SGhennadi Procopciuc /* This is used for floating-point precision calculations. */ 20b5101c45SGhennadi Procopciuc #define FP_PRECISION (100000000UL) 21b5101c45SGhennadi Procopciuc 228ab34357SGhennadi Procopciuc struct s32cc_clk_drv { 238ab34357SGhennadi Procopciuc uintptr_t fxosc_base; 24b5101c45SGhennadi Procopciuc uintptr_t armpll_base; 258ab34357SGhennadi Procopciuc }; 268ab34357SGhennadi Procopciuc 27d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth) 28d9373519SGhennadi Procopciuc { 29d9373519SGhennadi Procopciuc if (*depth == 0U) { 30d9373519SGhennadi Procopciuc return -ENOMEM; 31d9373519SGhennadi Procopciuc } 32d9373519SGhennadi Procopciuc 33d9373519SGhennadi Procopciuc (*depth)--; 34d9373519SGhennadi Procopciuc return 0; 35d9373519SGhennadi Procopciuc } 363a580e9eSGhennadi Procopciuc 378ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void) 388ab34357SGhennadi Procopciuc { 398ab34357SGhennadi Procopciuc static struct s32cc_clk_drv driver = { 408ab34357SGhennadi Procopciuc .fxosc_base = FXOSC_BASE_ADDR, 41b5101c45SGhennadi Procopciuc .armpll_base = ARMPLL_BASE_ADDR, 428ab34357SGhennadi Procopciuc }; 438ab34357SGhennadi Procopciuc 448ab34357SGhennadi Procopciuc return &driver; 458ab34357SGhennadi Procopciuc } 468ab34357SGhennadi Procopciuc 478ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth); 488ab34357SGhennadi Procopciuc 498ab34357SGhennadi Procopciuc static int enable_clk_module(const struct s32cc_clk_obj *module, 508ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 518ab34357SGhennadi Procopciuc unsigned int *depth) 528ab34357SGhennadi Procopciuc { 538ab34357SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 548ab34357SGhennadi Procopciuc int ret; 558ab34357SGhennadi Procopciuc 568ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 578ab34357SGhennadi Procopciuc if (ret != 0) { 588ab34357SGhennadi Procopciuc return ret; 598ab34357SGhennadi Procopciuc } 608ab34357SGhennadi Procopciuc 618ab34357SGhennadi Procopciuc if (clk == NULL) { 628ab34357SGhennadi Procopciuc return -EINVAL; 638ab34357SGhennadi Procopciuc } 648ab34357SGhennadi Procopciuc 658ab34357SGhennadi Procopciuc if (clk->module != NULL) { 668ab34357SGhennadi Procopciuc return enable_module(clk->module, depth); 678ab34357SGhennadi Procopciuc } 688ab34357SGhennadi Procopciuc 698ab34357SGhennadi Procopciuc if (clk->pclock != NULL) { 708ab34357SGhennadi Procopciuc return enable_clk_module(&clk->pclock->desc, drv, depth); 718ab34357SGhennadi Procopciuc } 728ab34357SGhennadi Procopciuc 738ab34357SGhennadi Procopciuc return -EINVAL; 748ab34357SGhennadi Procopciuc } 758ab34357SGhennadi Procopciuc 76b5101c45SGhennadi Procopciuc static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv, 77b5101c45SGhennadi Procopciuc uintptr_t *base) 78b5101c45SGhennadi Procopciuc { 79b5101c45SGhennadi Procopciuc int ret = 0; 80b5101c45SGhennadi Procopciuc 81b5101c45SGhennadi Procopciuc switch (id) { 82b5101c45SGhennadi Procopciuc case S32CC_FXOSC: 83b5101c45SGhennadi Procopciuc *base = drv->fxosc_base; 84b5101c45SGhennadi Procopciuc break; 85b5101c45SGhennadi Procopciuc case S32CC_ARM_PLL: 86b5101c45SGhennadi Procopciuc *base = drv->armpll_base; 87b5101c45SGhennadi Procopciuc break; 88b5101c45SGhennadi Procopciuc case S32CC_CGM1: 89b5101c45SGhennadi Procopciuc ret = -ENOTSUP; 90b5101c45SGhennadi Procopciuc break; 91b5101c45SGhennadi Procopciuc case S32CC_FIRC: 92b5101c45SGhennadi Procopciuc break; 93b5101c45SGhennadi Procopciuc case S32CC_SIRC: 94b5101c45SGhennadi Procopciuc break; 95b5101c45SGhennadi Procopciuc default: 96b5101c45SGhennadi Procopciuc ret = -EINVAL; 97b5101c45SGhennadi Procopciuc break; 98b5101c45SGhennadi Procopciuc } 99b5101c45SGhennadi Procopciuc 100b5101c45SGhennadi Procopciuc if (ret != 0) { 101b5101c45SGhennadi Procopciuc ERROR("Unknown clock source id: %u\n", id); 102b5101c45SGhennadi Procopciuc } 103b5101c45SGhennadi Procopciuc 104b5101c45SGhennadi Procopciuc return ret; 105b5101c45SGhennadi Procopciuc } 106b5101c45SGhennadi Procopciuc 1078ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv) 1088ab34357SGhennadi Procopciuc { 1098ab34357SGhennadi Procopciuc uintptr_t fxosc_base = drv->fxosc_base; 1108ab34357SGhennadi Procopciuc uint32_t ctrl; 1118ab34357SGhennadi Procopciuc 1128ab34357SGhennadi Procopciuc ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base)); 1138ab34357SGhennadi Procopciuc if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) { 1148ab34357SGhennadi Procopciuc return; 1158ab34357SGhennadi Procopciuc } 1168ab34357SGhennadi Procopciuc 1178ab34357SGhennadi Procopciuc ctrl = FXOSC_CTRL_COMP_EN; 1188ab34357SGhennadi Procopciuc ctrl &= ~FXOSC_CTRL_OSC_BYP; 1198ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_EOCV(0x1); 1208ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_GM_SEL(0x7); 1218ab34357SGhennadi Procopciuc mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl); 1228ab34357SGhennadi Procopciuc 1238ab34357SGhennadi Procopciuc /* Switch ON the crystal oscillator. */ 1248ab34357SGhennadi Procopciuc mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON); 1258ab34357SGhennadi Procopciuc 1268ab34357SGhennadi Procopciuc /* Wait until the clock is stable. */ 1278ab34357SGhennadi Procopciuc while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) { 1288ab34357SGhennadi Procopciuc } 1298ab34357SGhennadi Procopciuc } 1308ab34357SGhennadi Procopciuc 1318ab34357SGhennadi Procopciuc static int enable_osc(const struct s32cc_clk_obj *module, 1328ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1338ab34357SGhennadi Procopciuc unsigned int *depth) 1348ab34357SGhennadi Procopciuc { 1358ab34357SGhennadi Procopciuc const struct s32cc_osc *osc = s32cc_obj2osc(module); 1368ab34357SGhennadi Procopciuc int ret = 0; 1378ab34357SGhennadi Procopciuc 1388ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1398ab34357SGhennadi Procopciuc if (ret != 0) { 1408ab34357SGhennadi Procopciuc return ret; 1418ab34357SGhennadi Procopciuc } 1428ab34357SGhennadi Procopciuc 1438ab34357SGhennadi Procopciuc switch (osc->source) { 1448ab34357SGhennadi Procopciuc case S32CC_FXOSC: 1458ab34357SGhennadi Procopciuc enable_fxosc(drv); 1468ab34357SGhennadi Procopciuc break; 1478ab34357SGhennadi Procopciuc /* FIRC and SIRC oscillators are enabled by default */ 1488ab34357SGhennadi Procopciuc case S32CC_FIRC: 1498ab34357SGhennadi Procopciuc break; 1508ab34357SGhennadi Procopciuc case S32CC_SIRC: 1518ab34357SGhennadi Procopciuc break; 1528ab34357SGhennadi Procopciuc default: 1538ab34357SGhennadi Procopciuc ERROR("Invalid oscillator %d\n", osc->source); 1548ab34357SGhennadi Procopciuc ret = -EINVAL; 1558ab34357SGhennadi Procopciuc break; 1568ab34357SGhennadi Procopciuc }; 1578ab34357SGhennadi Procopciuc 1588ab34357SGhennadi Procopciuc return ret; 1598ab34357SGhennadi Procopciuc } 1608ab34357SGhennadi Procopciuc 161b5101c45SGhennadi Procopciuc static int get_pll_mfi_mfn(unsigned long pll_vco, unsigned long ref_freq, 162b5101c45SGhennadi Procopciuc uint32_t *mfi, uint32_t *mfn) 163b5101c45SGhennadi Procopciuc 164b5101c45SGhennadi Procopciuc { 165b5101c45SGhennadi Procopciuc unsigned long vco; 166b5101c45SGhennadi Procopciuc unsigned long mfn64; 167b5101c45SGhennadi Procopciuc 168b5101c45SGhennadi Procopciuc /* FRAC-N mode */ 169b5101c45SGhennadi Procopciuc *mfi = (uint32_t)(pll_vco / ref_freq); 170b5101c45SGhennadi Procopciuc 171b5101c45SGhennadi Procopciuc /* MFN formula : (double)(pll_vco % ref_freq) / ref_freq * 18432.0 */ 172b5101c45SGhennadi Procopciuc mfn64 = pll_vco % ref_freq; 173b5101c45SGhennadi Procopciuc mfn64 *= FP_PRECISION; 174b5101c45SGhennadi Procopciuc mfn64 /= ref_freq; 175b5101c45SGhennadi Procopciuc mfn64 *= 18432UL; 176b5101c45SGhennadi Procopciuc mfn64 /= FP_PRECISION; 177b5101c45SGhennadi Procopciuc 178b5101c45SGhennadi Procopciuc if (mfn64 > UINT32_MAX) { 179b5101c45SGhennadi Procopciuc return -EINVAL; 180b5101c45SGhennadi Procopciuc } 181b5101c45SGhennadi Procopciuc 182b5101c45SGhennadi Procopciuc *mfn = (uint32_t)mfn64; 183b5101c45SGhennadi Procopciuc 184b5101c45SGhennadi Procopciuc vco = ((unsigned long)*mfn * FP_PRECISION) / 18432UL; 185b5101c45SGhennadi Procopciuc vco += (unsigned long)*mfi * FP_PRECISION; 186b5101c45SGhennadi Procopciuc vco *= ref_freq; 187b5101c45SGhennadi Procopciuc vco /= FP_PRECISION; 188b5101c45SGhennadi Procopciuc 189b5101c45SGhennadi Procopciuc if (vco != pll_vco) { 190b5101c45SGhennadi Procopciuc ERROR("Failed to find MFI and MFN settings for PLL freq %lu. Nearest freq = %lu\n", 191b5101c45SGhennadi Procopciuc pll_vco, vco); 192b5101c45SGhennadi Procopciuc return -EINVAL; 193b5101c45SGhennadi Procopciuc } 194b5101c45SGhennadi Procopciuc 195b5101c45SGhennadi Procopciuc return 0; 196b5101c45SGhennadi Procopciuc } 197b5101c45SGhennadi Procopciuc 198b5101c45SGhennadi Procopciuc static struct s32cc_clkmux *get_pll_mux(const struct s32cc_pll *pll) 199b5101c45SGhennadi Procopciuc { 200b5101c45SGhennadi Procopciuc const struct s32cc_clk_obj *source = pll->source; 201b5101c45SGhennadi Procopciuc const struct s32cc_clk *clk; 202b5101c45SGhennadi Procopciuc 203b5101c45SGhennadi Procopciuc if (source == NULL) { 204b5101c45SGhennadi Procopciuc ERROR("Failed to identify PLL's parent\n"); 205b5101c45SGhennadi Procopciuc return NULL; 206b5101c45SGhennadi Procopciuc } 207b5101c45SGhennadi Procopciuc 208b5101c45SGhennadi Procopciuc if (source->type != s32cc_clk_t) { 209b5101c45SGhennadi Procopciuc ERROR("The parent of the PLL isn't a clock\n"); 210b5101c45SGhennadi Procopciuc return NULL; 211b5101c45SGhennadi Procopciuc } 212b5101c45SGhennadi Procopciuc 213b5101c45SGhennadi Procopciuc clk = s32cc_obj2clk(source); 214b5101c45SGhennadi Procopciuc 215b5101c45SGhennadi Procopciuc if (clk->module == NULL) { 216b5101c45SGhennadi Procopciuc ERROR("The clock isn't connected to a module\n"); 217b5101c45SGhennadi Procopciuc return NULL; 218b5101c45SGhennadi Procopciuc } 219b5101c45SGhennadi Procopciuc 220b5101c45SGhennadi Procopciuc source = clk->module; 221b5101c45SGhennadi Procopciuc 222b5101c45SGhennadi Procopciuc if ((source->type != s32cc_clkmux_t) && 223b5101c45SGhennadi Procopciuc (source->type != s32cc_shared_clkmux_t)) { 224b5101c45SGhennadi Procopciuc ERROR("The parent of the PLL isn't a MUX\n"); 225b5101c45SGhennadi Procopciuc return NULL; 226b5101c45SGhennadi Procopciuc } 227b5101c45SGhennadi Procopciuc 228b5101c45SGhennadi Procopciuc return s32cc_obj2clkmux(source); 229b5101c45SGhennadi Procopciuc } 230b5101c45SGhennadi Procopciuc 231b5101c45SGhennadi Procopciuc static void disable_odiv(uintptr_t pll_addr, uint32_t div_index) 232b5101c45SGhennadi Procopciuc { 233b5101c45SGhennadi Procopciuc mmio_clrbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE); 234b5101c45SGhennadi Procopciuc } 235b5101c45SGhennadi Procopciuc 236*84e82085SGhennadi Procopciuc static void enable_odiv(uintptr_t pll_addr, uint32_t div_index) 237*84e82085SGhennadi Procopciuc { 238*84e82085SGhennadi Procopciuc mmio_setbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE); 239*84e82085SGhennadi Procopciuc } 240*84e82085SGhennadi Procopciuc 241b5101c45SGhennadi Procopciuc static void disable_odivs(uintptr_t pll_addr, uint32_t ndivs) 242b5101c45SGhennadi Procopciuc { 243b5101c45SGhennadi Procopciuc uint32_t i; 244b5101c45SGhennadi Procopciuc 245b5101c45SGhennadi Procopciuc for (i = 0; i < ndivs; i++) { 246b5101c45SGhennadi Procopciuc disable_odiv(pll_addr, i); 247b5101c45SGhennadi Procopciuc } 248b5101c45SGhennadi Procopciuc } 249b5101c45SGhennadi Procopciuc 250b5101c45SGhennadi Procopciuc static void enable_pll_hw(uintptr_t pll_addr) 251b5101c45SGhennadi Procopciuc { 252b5101c45SGhennadi Procopciuc /* Enable the PLL. */ 253b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLCR(pll_addr), 0x0); 254b5101c45SGhennadi Procopciuc 255b5101c45SGhennadi Procopciuc /* Poll until PLL acquires lock. */ 256b5101c45SGhennadi Procopciuc while ((mmio_read_32(PLLDIG_PLLSR(pll_addr)) & PLLDIG_PLLSR_LOCK) == 0U) { 257b5101c45SGhennadi Procopciuc } 258b5101c45SGhennadi Procopciuc } 259b5101c45SGhennadi Procopciuc 260b5101c45SGhennadi Procopciuc static void disable_pll_hw(uintptr_t pll_addr) 261b5101c45SGhennadi Procopciuc { 262b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLCR(pll_addr), PLLDIG_PLLCR_PLLPD); 263b5101c45SGhennadi Procopciuc } 264b5101c45SGhennadi Procopciuc 265b5101c45SGhennadi Procopciuc static int program_pll(const struct s32cc_pll *pll, uintptr_t pll_addr, 266b5101c45SGhennadi Procopciuc const struct s32cc_clk_drv *drv, uint32_t sclk_id, 267b5101c45SGhennadi Procopciuc unsigned long sclk_freq) 268b5101c45SGhennadi Procopciuc { 269b5101c45SGhennadi Procopciuc uint32_t rdiv = 1, mfi, mfn; 270b5101c45SGhennadi Procopciuc int ret; 271b5101c45SGhennadi Procopciuc 272b5101c45SGhennadi Procopciuc ret = get_pll_mfi_mfn(pll->vco_freq, sclk_freq, &mfi, &mfn); 273b5101c45SGhennadi Procopciuc if (ret != 0) { 274b5101c45SGhennadi Procopciuc return -EINVAL; 275b5101c45SGhennadi Procopciuc } 276b5101c45SGhennadi Procopciuc 277b5101c45SGhennadi Procopciuc /* Disable ODIVs*/ 278b5101c45SGhennadi Procopciuc disable_odivs(pll_addr, pll->ndividers); 279b5101c45SGhennadi Procopciuc 280b5101c45SGhennadi Procopciuc /* Disable PLL */ 281b5101c45SGhennadi Procopciuc disable_pll_hw(pll_addr); 282b5101c45SGhennadi Procopciuc 283b5101c45SGhennadi Procopciuc /* Program PLLCLKMUX */ 284b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLCLKMUX(pll_addr), sclk_id); 285b5101c45SGhennadi Procopciuc 286b5101c45SGhennadi Procopciuc /* Program VCO */ 287b5101c45SGhennadi Procopciuc mmio_clrsetbits_32(PLLDIG_PLLDV(pll_addr), 288b5101c45SGhennadi Procopciuc PLLDIG_PLLDV_RDIV_MASK | PLLDIG_PLLDV_MFI_MASK, 289b5101c45SGhennadi Procopciuc PLLDIG_PLLDV_RDIV_SET(rdiv) | PLLDIG_PLLDV_MFI(mfi)); 290b5101c45SGhennadi Procopciuc 291b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLFD(pll_addr), 292b5101c45SGhennadi Procopciuc PLLDIG_PLLFD_MFN_SET(mfn) | PLLDIG_PLLFD_SMDEN); 293b5101c45SGhennadi Procopciuc 294b5101c45SGhennadi Procopciuc enable_pll_hw(pll_addr); 295b5101c45SGhennadi Procopciuc 296b5101c45SGhennadi Procopciuc return ret; 297b5101c45SGhennadi Procopciuc } 298b5101c45SGhennadi Procopciuc 299b5101c45SGhennadi Procopciuc static int enable_pll(const struct s32cc_clk_obj *module, 300b5101c45SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 301b5101c45SGhennadi Procopciuc unsigned int *depth) 302b5101c45SGhennadi Procopciuc { 303b5101c45SGhennadi Procopciuc const struct s32cc_pll *pll = s32cc_obj2pll(module); 304b5101c45SGhennadi Procopciuc const struct s32cc_clkmux *mux; 305b5101c45SGhennadi Procopciuc uintptr_t pll_addr = UL(0x0); 306b5101c45SGhennadi Procopciuc unsigned long sclk_freq; 307b5101c45SGhennadi Procopciuc uint32_t sclk_id; 308b5101c45SGhennadi Procopciuc int ret; 309b5101c45SGhennadi Procopciuc 310b5101c45SGhennadi Procopciuc ret = update_stack_depth(depth); 311b5101c45SGhennadi Procopciuc if (ret != 0) { 312b5101c45SGhennadi Procopciuc return ret; 313b5101c45SGhennadi Procopciuc } 314b5101c45SGhennadi Procopciuc 315b5101c45SGhennadi Procopciuc mux = get_pll_mux(pll); 316b5101c45SGhennadi Procopciuc if (mux == NULL) { 317b5101c45SGhennadi Procopciuc return -EINVAL; 318b5101c45SGhennadi Procopciuc } 319b5101c45SGhennadi Procopciuc 320b5101c45SGhennadi Procopciuc if (pll->instance != mux->module) { 321b5101c45SGhennadi Procopciuc ERROR("MUX type is not in sync with PLL ID\n"); 322b5101c45SGhennadi Procopciuc return -EINVAL; 323b5101c45SGhennadi Procopciuc } 324b5101c45SGhennadi Procopciuc 325b5101c45SGhennadi Procopciuc ret = get_base_addr(pll->instance, drv, &pll_addr); 326b5101c45SGhennadi Procopciuc if (ret != 0) { 327b5101c45SGhennadi Procopciuc ERROR("Failed to detect PLL instance\n"); 328b5101c45SGhennadi Procopciuc return ret; 329b5101c45SGhennadi Procopciuc } 330b5101c45SGhennadi Procopciuc 331b5101c45SGhennadi Procopciuc switch (mux->source_id) { 332b5101c45SGhennadi Procopciuc case S32CC_CLK_FIRC: 333b5101c45SGhennadi Procopciuc sclk_freq = 48U * MHZ; 334b5101c45SGhennadi Procopciuc sclk_id = 0; 335b5101c45SGhennadi Procopciuc break; 336b5101c45SGhennadi Procopciuc case S32CC_CLK_FXOSC: 337b5101c45SGhennadi Procopciuc sclk_freq = 40U * MHZ; 338b5101c45SGhennadi Procopciuc sclk_id = 1; 339b5101c45SGhennadi Procopciuc break; 340b5101c45SGhennadi Procopciuc default: 341b5101c45SGhennadi Procopciuc ERROR("Invalid source selection for PLL 0x%lx\n", 342b5101c45SGhennadi Procopciuc pll_addr); 343b5101c45SGhennadi Procopciuc return -EINVAL; 344b5101c45SGhennadi Procopciuc }; 345b5101c45SGhennadi Procopciuc 346b5101c45SGhennadi Procopciuc return program_pll(pll, pll_addr, drv, sclk_id, sclk_freq); 347b5101c45SGhennadi Procopciuc } 348b5101c45SGhennadi Procopciuc 349*84e82085SGhennadi Procopciuc static inline struct s32cc_pll *get_div_pll(const struct s32cc_pll_out_div *pdiv) 350*84e82085SGhennadi Procopciuc { 351*84e82085SGhennadi Procopciuc const struct s32cc_clk_obj *parent; 352*84e82085SGhennadi Procopciuc 353*84e82085SGhennadi Procopciuc parent = pdiv->parent; 354*84e82085SGhennadi Procopciuc if (parent == NULL) { 355*84e82085SGhennadi Procopciuc ERROR("Failed to identify PLL divider's parent\n"); 356*84e82085SGhennadi Procopciuc return NULL; 357*84e82085SGhennadi Procopciuc } 358*84e82085SGhennadi Procopciuc 359*84e82085SGhennadi Procopciuc if (parent->type != s32cc_pll_t) { 360*84e82085SGhennadi Procopciuc ERROR("The parent of the divider is not a PLL instance\n"); 361*84e82085SGhennadi Procopciuc return NULL; 362*84e82085SGhennadi Procopciuc } 363*84e82085SGhennadi Procopciuc 364*84e82085SGhennadi Procopciuc return s32cc_obj2pll(parent); 365*84e82085SGhennadi Procopciuc } 366*84e82085SGhennadi Procopciuc 367*84e82085SGhennadi Procopciuc static void config_pll_out_div(uintptr_t pll_addr, uint32_t div_index, uint32_t dc) 368*84e82085SGhennadi Procopciuc { 369*84e82085SGhennadi Procopciuc uint32_t pllodiv; 370*84e82085SGhennadi Procopciuc uint32_t pdiv; 371*84e82085SGhennadi Procopciuc 372*84e82085SGhennadi Procopciuc pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, div_index)); 373*84e82085SGhennadi Procopciuc pdiv = PLLDIG_PLLODIV_DIV(pllodiv); 374*84e82085SGhennadi Procopciuc 375*84e82085SGhennadi Procopciuc if (((pdiv + 1U) == dc) && ((pllodiv & PLLDIG_PLLODIV_DE) != 0U)) { 376*84e82085SGhennadi Procopciuc return; 377*84e82085SGhennadi Procopciuc } 378*84e82085SGhennadi Procopciuc 379*84e82085SGhennadi Procopciuc if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) { 380*84e82085SGhennadi Procopciuc disable_odiv(pll_addr, div_index); 381*84e82085SGhennadi Procopciuc } 382*84e82085SGhennadi Procopciuc 383*84e82085SGhennadi Procopciuc pllodiv = PLLDIG_PLLODIV_DIV_SET(dc - 1U); 384*84e82085SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLODIV(pll_addr, div_index), pllodiv); 385*84e82085SGhennadi Procopciuc 386*84e82085SGhennadi Procopciuc enable_odiv(pll_addr, div_index); 387*84e82085SGhennadi Procopciuc } 388*84e82085SGhennadi Procopciuc 389*84e82085SGhennadi Procopciuc static int enable_pll_div(const struct s32cc_clk_obj *module, 390*84e82085SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 391*84e82085SGhennadi Procopciuc unsigned int *depth) 392*84e82085SGhennadi Procopciuc { 393*84e82085SGhennadi Procopciuc const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 394*84e82085SGhennadi Procopciuc uintptr_t pll_addr = 0x0ULL; 395*84e82085SGhennadi Procopciuc const struct s32cc_pll *pll; 396*84e82085SGhennadi Procopciuc uint32_t dc; 397*84e82085SGhennadi Procopciuc int ret; 398*84e82085SGhennadi Procopciuc 399*84e82085SGhennadi Procopciuc ret = update_stack_depth(depth); 400*84e82085SGhennadi Procopciuc if (ret != 0) { 401*84e82085SGhennadi Procopciuc return ret; 402*84e82085SGhennadi Procopciuc } 403*84e82085SGhennadi Procopciuc 404*84e82085SGhennadi Procopciuc pll = get_div_pll(pdiv); 405*84e82085SGhennadi Procopciuc if (pll == NULL) { 406*84e82085SGhennadi Procopciuc ERROR("The parent of the PLL DIV is invalid\n"); 407*84e82085SGhennadi Procopciuc return 0; 408*84e82085SGhennadi Procopciuc } 409*84e82085SGhennadi Procopciuc 410*84e82085SGhennadi Procopciuc ret = get_base_addr(pll->instance, drv, &pll_addr); 411*84e82085SGhennadi Procopciuc if (ret != 0) { 412*84e82085SGhennadi Procopciuc ERROR("Failed to detect PLL instance\n"); 413*84e82085SGhennadi Procopciuc return -EINVAL; 414*84e82085SGhennadi Procopciuc } 415*84e82085SGhennadi Procopciuc 416*84e82085SGhennadi Procopciuc dc = (uint32_t)(pll->vco_freq / pdiv->freq); 417*84e82085SGhennadi Procopciuc 418*84e82085SGhennadi Procopciuc config_pll_out_div(pll_addr, pdiv->index, dc); 419*84e82085SGhennadi Procopciuc 420*84e82085SGhennadi Procopciuc return 0; 421*84e82085SGhennadi Procopciuc } 422*84e82085SGhennadi Procopciuc 4238ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth) 4248ab34357SGhennadi Procopciuc { 4258ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv = get_drv(); 4268ab34357SGhennadi Procopciuc int ret = 0; 4278ab34357SGhennadi Procopciuc 4288ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 4298ab34357SGhennadi Procopciuc if (ret != 0) { 4308ab34357SGhennadi Procopciuc return ret; 4318ab34357SGhennadi Procopciuc } 4328ab34357SGhennadi Procopciuc 4338ab34357SGhennadi Procopciuc if (drv == NULL) { 4348ab34357SGhennadi Procopciuc return -EINVAL; 4358ab34357SGhennadi Procopciuc } 4368ab34357SGhennadi Procopciuc 4378ab34357SGhennadi Procopciuc switch (module->type) { 4388ab34357SGhennadi Procopciuc case s32cc_osc_t: 4398ab34357SGhennadi Procopciuc ret = enable_osc(module, drv, depth); 4408ab34357SGhennadi Procopciuc break; 4418ab34357SGhennadi Procopciuc case s32cc_clk_t: 4428ab34357SGhennadi Procopciuc ret = enable_clk_module(module, drv, depth); 4438ab34357SGhennadi Procopciuc break; 444b5101c45SGhennadi Procopciuc case s32cc_pll_t: 445b5101c45SGhennadi Procopciuc ret = enable_pll(module, drv, depth); 446b5101c45SGhennadi Procopciuc break; 447*84e82085SGhennadi Procopciuc case s32cc_pll_out_div_t: 448*84e82085SGhennadi Procopciuc ret = enable_pll_div(module, drv, depth); 449*84e82085SGhennadi Procopciuc break; 450a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 451a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 452a8be748aSGhennadi Procopciuc break; 4533fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 4543fa91a94SGhennadi Procopciuc ret = -ENOTSUP; 4553fa91a94SGhennadi Procopciuc break; 45644e2130aSGhennadi Procopciuc case s32cc_fixed_div_t: 457a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 458a8be748aSGhennadi Procopciuc break; 4598ab34357SGhennadi Procopciuc default: 4608ab34357SGhennadi Procopciuc ret = -EINVAL; 4618ab34357SGhennadi Procopciuc break; 4628ab34357SGhennadi Procopciuc } 4638ab34357SGhennadi Procopciuc 4648ab34357SGhennadi Procopciuc return ret; 4658ab34357SGhennadi Procopciuc } 4668ab34357SGhennadi Procopciuc 4673a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id) 4683a580e9eSGhennadi Procopciuc { 4698ab34357SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 4708ab34357SGhennadi Procopciuc const struct s32cc_clk *clk; 4718ab34357SGhennadi Procopciuc 4728ab34357SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 4738ab34357SGhennadi Procopciuc if (clk == NULL) { 4748ab34357SGhennadi Procopciuc return -EINVAL; 4758ab34357SGhennadi Procopciuc } 4768ab34357SGhennadi Procopciuc 4778ab34357SGhennadi Procopciuc return enable_module(&clk->desc, &depth); 4783a580e9eSGhennadi Procopciuc } 4793a580e9eSGhennadi Procopciuc 4803a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id) 4813a580e9eSGhennadi Procopciuc { 4823a580e9eSGhennadi Procopciuc } 4833a580e9eSGhennadi Procopciuc 4843a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id) 4853a580e9eSGhennadi Procopciuc { 4863a580e9eSGhennadi Procopciuc return false; 4873a580e9eSGhennadi Procopciuc } 4883a580e9eSGhennadi Procopciuc 4893a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id) 4903a580e9eSGhennadi Procopciuc { 4913a580e9eSGhennadi Procopciuc return 0; 4923a580e9eSGhennadi Procopciuc } 4933a580e9eSGhennadi Procopciuc 494d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 495d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 496d9373519SGhennadi Procopciuc unsigned int *depth); 497d9373519SGhennadi Procopciuc 498d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate, 499d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 500d9373519SGhennadi Procopciuc { 501d9373519SGhennadi Procopciuc struct s32cc_osc *osc = s32cc_obj2osc(module); 502d9373519SGhennadi Procopciuc int ret; 503d9373519SGhennadi Procopciuc 504d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 505d9373519SGhennadi Procopciuc if (ret != 0) { 506d9373519SGhennadi Procopciuc return ret; 507d9373519SGhennadi Procopciuc } 508d9373519SGhennadi Procopciuc 509d9373519SGhennadi Procopciuc if ((osc->freq != 0UL) && (rate != osc->freq)) { 510d9373519SGhennadi Procopciuc ERROR("Already initialized oscillator. freq = %lu\n", 511d9373519SGhennadi Procopciuc osc->freq); 512d9373519SGhennadi Procopciuc return -EINVAL; 513d9373519SGhennadi Procopciuc } 514d9373519SGhennadi Procopciuc 515d9373519SGhennadi Procopciuc osc->freq = rate; 516d9373519SGhennadi Procopciuc *orate = osc->freq; 517d9373519SGhennadi Procopciuc 518d9373519SGhennadi Procopciuc return 0; 519d9373519SGhennadi Procopciuc } 520d9373519SGhennadi Procopciuc 521d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate, 522d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 523d9373519SGhennadi Procopciuc { 524d9373519SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 525d9373519SGhennadi Procopciuc int ret; 526d9373519SGhennadi Procopciuc 527d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 528d9373519SGhennadi Procopciuc if (ret != 0) { 529d9373519SGhennadi Procopciuc return ret; 530d9373519SGhennadi Procopciuc } 531d9373519SGhennadi Procopciuc 532d9373519SGhennadi Procopciuc if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) && 533d9373519SGhennadi Procopciuc ((rate < clk->min_freq) || (rate > clk->max_freq))) { 534d9373519SGhennadi Procopciuc ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n", 535d9373519SGhennadi Procopciuc rate, clk->min_freq, clk->max_freq); 536d9373519SGhennadi Procopciuc return -EINVAL; 537d9373519SGhennadi Procopciuc } 538d9373519SGhennadi Procopciuc 539d9373519SGhennadi Procopciuc if (clk->module != NULL) { 540d9373519SGhennadi Procopciuc return set_module_rate(clk->module, rate, orate, depth); 541d9373519SGhennadi Procopciuc } 542d9373519SGhennadi Procopciuc 543d9373519SGhennadi Procopciuc if (clk->pclock != NULL) { 544d9373519SGhennadi Procopciuc return set_clk_freq(&clk->pclock->desc, rate, orate, depth); 545d9373519SGhennadi Procopciuc } 546d9373519SGhennadi Procopciuc 547d9373519SGhennadi Procopciuc return -EINVAL; 548d9373519SGhennadi Procopciuc } 549d9373519SGhennadi Procopciuc 5507ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate, 5517ad4e231SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 5527ad4e231SGhennadi Procopciuc { 5537ad4e231SGhennadi Procopciuc struct s32cc_pll *pll = s32cc_obj2pll(module); 5547ad4e231SGhennadi Procopciuc int ret; 5557ad4e231SGhennadi Procopciuc 5567ad4e231SGhennadi Procopciuc ret = update_stack_depth(depth); 5577ad4e231SGhennadi Procopciuc if (ret != 0) { 5587ad4e231SGhennadi Procopciuc return ret; 5597ad4e231SGhennadi Procopciuc } 5607ad4e231SGhennadi Procopciuc 5617ad4e231SGhennadi Procopciuc if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) { 5627ad4e231SGhennadi Procopciuc ERROR("PLL frequency was already set\n"); 5637ad4e231SGhennadi Procopciuc return -EINVAL; 5647ad4e231SGhennadi Procopciuc } 5657ad4e231SGhennadi Procopciuc 5667ad4e231SGhennadi Procopciuc pll->vco_freq = rate; 5677ad4e231SGhennadi Procopciuc *orate = pll->vco_freq; 5687ad4e231SGhennadi Procopciuc 5697ad4e231SGhennadi Procopciuc return 0; 5707ad4e231SGhennadi Procopciuc } 5717ad4e231SGhennadi Procopciuc 572de950ef0SGhennadi Procopciuc static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 573de950ef0SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 574de950ef0SGhennadi Procopciuc { 575de950ef0SGhennadi Procopciuc struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 576de950ef0SGhennadi Procopciuc const struct s32cc_pll *pll; 577de950ef0SGhennadi Procopciuc unsigned long prate, dc; 578de950ef0SGhennadi Procopciuc int ret; 579de950ef0SGhennadi Procopciuc 580de950ef0SGhennadi Procopciuc ret = update_stack_depth(depth); 581de950ef0SGhennadi Procopciuc if (ret != 0) { 582de950ef0SGhennadi Procopciuc return ret; 583de950ef0SGhennadi Procopciuc } 584de950ef0SGhennadi Procopciuc 585de950ef0SGhennadi Procopciuc if (pdiv->parent == NULL) { 586de950ef0SGhennadi Procopciuc ERROR("Failed to identify PLL divider's parent\n"); 587de950ef0SGhennadi Procopciuc return -EINVAL; 588de950ef0SGhennadi Procopciuc } 589de950ef0SGhennadi Procopciuc 590de950ef0SGhennadi Procopciuc pll = s32cc_obj2pll(pdiv->parent); 591de950ef0SGhennadi Procopciuc if (pll == NULL) { 592de950ef0SGhennadi Procopciuc ERROR("The parent of the PLL DIV is invalid\n"); 593de950ef0SGhennadi Procopciuc return -EINVAL; 594de950ef0SGhennadi Procopciuc } 595de950ef0SGhennadi Procopciuc 596de950ef0SGhennadi Procopciuc prate = pll->vco_freq; 597de950ef0SGhennadi Procopciuc 598de950ef0SGhennadi Procopciuc /** 599de950ef0SGhennadi Procopciuc * The PLL is not initialized yet, so let's take a risk 600de950ef0SGhennadi Procopciuc * and accept the proposed rate. 601de950ef0SGhennadi Procopciuc */ 602de950ef0SGhennadi Procopciuc if (prate == 0UL) { 603de950ef0SGhennadi Procopciuc pdiv->freq = rate; 604de950ef0SGhennadi Procopciuc *orate = rate; 605de950ef0SGhennadi Procopciuc return 0; 606de950ef0SGhennadi Procopciuc } 607de950ef0SGhennadi Procopciuc 608de950ef0SGhennadi Procopciuc /* Decline in case the rate cannot fit PLL's requirements. */ 609de950ef0SGhennadi Procopciuc dc = prate / rate; 610de950ef0SGhennadi Procopciuc if ((prate / dc) != rate) { 611de950ef0SGhennadi Procopciuc return -EINVAL; 612de950ef0SGhennadi Procopciuc } 613de950ef0SGhennadi Procopciuc 614de950ef0SGhennadi Procopciuc pdiv->freq = rate; 615de950ef0SGhennadi Procopciuc *orate = pdiv->freq; 616de950ef0SGhennadi Procopciuc 617de950ef0SGhennadi Procopciuc return 0; 618de950ef0SGhennadi Procopciuc } 619de950ef0SGhennadi Procopciuc 62065739db2SGhennadi Procopciuc static int set_fixed_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 62165739db2SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 62265739db2SGhennadi Procopciuc { 62365739db2SGhennadi Procopciuc const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module); 62465739db2SGhennadi Procopciuc int ret; 62565739db2SGhennadi Procopciuc 62665739db2SGhennadi Procopciuc ret = update_stack_depth(depth); 62765739db2SGhennadi Procopciuc if (ret != 0) { 62865739db2SGhennadi Procopciuc return ret; 62965739db2SGhennadi Procopciuc } 63065739db2SGhennadi Procopciuc 63165739db2SGhennadi Procopciuc if (fdiv->parent == NULL) { 63265739db2SGhennadi Procopciuc ERROR("The divider doesn't have a valid parent\b"); 63365739db2SGhennadi Procopciuc return -EINVAL; 63465739db2SGhennadi Procopciuc } 63565739db2SGhennadi Procopciuc 63665739db2SGhennadi Procopciuc ret = set_module_rate(fdiv->parent, rate * fdiv->rate_div, orate, depth); 63765739db2SGhennadi Procopciuc 63865739db2SGhennadi Procopciuc /* Update the output rate based on the parent's rate */ 63965739db2SGhennadi Procopciuc *orate /= fdiv->rate_div; 64065739db2SGhennadi Procopciuc 64165739db2SGhennadi Procopciuc return ret; 64265739db2SGhennadi Procopciuc } 64365739db2SGhennadi Procopciuc 64464e0c226SGhennadi Procopciuc static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate, 64564e0c226SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 64664e0c226SGhennadi Procopciuc { 64764e0c226SGhennadi Procopciuc const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); 64864e0c226SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id); 64964e0c226SGhennadi Procopciuc int ret; 65064e0c226SGhennadi Procopciuc 65164e0c226SGhennadi Procopciuc ret = update_stack_depth(depth); 65264e0c226SGhennadi Procopciuc if (ret != 0) { 65364e0c226SGhennadi Procopciuc return ret; 65464e0c226SGhennadi Procopciuc } 65564e0c226SGhennadi Procopciuc 65664e0c226SGhennadi Procopciuc if (clk == NULL) { 65764e0c226SGhennadi Procopciuc ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n", 65864e0c226SGhennadi Procopciuc mux->index, mux->source_id); 65964e0c226SGhennadi Procopciuc return -EINVAL; 66064e0c226SGhennadi Procopciuc } 66164e0c226SGhennadi Procopciuc 66264e0c226SGhennadi Procopciuc return set_module_rate(&clk->desc, rate, orate, depth); 66364e0c226SGhennadi Procopciuc } 66464e0c226SGhennadi Procopciuc 665d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 666d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 667d9373519SGhennadi Procopciuc unsigned int *depth) 668d9373519SGhennadi Procopciuc { 669d9373519SGhennadi Procopciuc int ret = 0; 670d9373519SGhennadi Procopciuc 671d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 672d9373519SGhennadi Procopciuc if (ret != 0) { 673d9373519SGhennadi Procopciuc return ret; 674d9373519SGhennadi Procopciuc } 675d9373519SGhennadi Procopciuc 676d9373519SGhennadi Procopciuc switch (module->type) { 677d9373519SGhennadi Procopciuc case s32cc_clk_t: 678d9373519SGhennadi Procopciuc ret = set_clk_freq(module, rate, orate, depth); 679d9373519SGhennadi Procopciuc break; 680d9373519SGhennadi Procopciuc case s32cc_osc_t: 681d9373519SGhennadi Procopciuc ret = set_osc_freq(module, rate, orate, depth); 682d9373519SGhennadi Procopciuc break; 6837ad4e231SGhennadi Procopciuc case s32cc_pll_t: 6847ad4e231SGhennadi Procopciuc ret = set_pll_freq(module, rate, orate, depth); 6857ad4e231SGhennadi Procopciuc break; 686de950ef0SGhennadi Procopciuc case s32cc_pll_out_div_t: 687de950ef0SGhennadi Procopciuc ret = set_pll_div_freq(module, rate, orate, depth); 688de950ef0SGhennadi Procopciuc break; 68965739db2SGhennadi Procopciuc case s32cc_fixed_div_t: 69065739db2SGhennadi Procopciuc ret = set_fixed_div_freq(module, rate, orate, depth); 69165739db2SGhennadi Procopciuc break; 692a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 69364e0c226SGhennadi Procopciuc ret = set_mux_freq(module, rate, orate, depth); 69464e0c226SGhennadi Procopciuc break; 6953fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 69664e0c226SGhennadi Procopciuc ret = set_mux_freq(module, rate, orate, depth); 697a8be748aSGhennadi Procopciuc break; 698d9373519SGhennadi Procopciuc default: 699d9373519SGhennadi Procopciuc ret = -EINVAL; 700d9373519SGhennadi Procopciuc break; 701d9373519SGhennadi Procopciuc } 702d9373519SGhennadi Procopciuc 703d9373519SGhennadi Procopciuc return ret; 704d9373519SGhennadi Procopciuc } 705d9373519SGhennadi Procopciuc 7063a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate, 7073a580e9eSGhennadi Procopciuc unsigned long *orate) 7083a580e9eSGhennadi Procopciuc { 709d9373519SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 710d9373519SGhennadi Procopciuc const struct s32cc_clk *clk; 711d9373519SGhennadi Procopciuc int ret; 712d9373519SGhennadi Procopciuc 713d9373519SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 714d9373519SGhennadi Procopciuc if (clk == NULL) { 715d9373519SGhennadi Procopciuc return -EINVAL; 716d9373519SGhennadi Procopciuc } 717d9373519SGhennadi Procopciuc 718d9373519SGhennadi Procopciuc ret = set_module_rate(&clk->desc, rate, orate, &depth); 719d9373519SGhennadi Procopciuc if (ret != 0) { 720d9373519SGhennadi Procopciuc ERROR("Failed to set frequency (%lu MHz) for clock %lu\n", 721d9373519SGhennadi Procopciuc rate, id); 722d9373519SGhennadi Procopciuc } 723d9373519SGhennadi Procopciuc 724d9373519SGhennadi Procopciuc return ret; 7253a580e9eSGhennadi Procopciuc } 7263a580e9eSGhennadi Procopciuc 7273a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id) 7283a580e9eSGhennadi Procopciuc { 7293a580e9eSGhennadi Procopciuc return -ENOTSUP; 7303a580e9eSGhennadi Procopciuc } 7313a580e9eSGhennadi Procopciuc 7323a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id) 7333a580e9eSGhennadi Procopciuc { 73412e7a2cdSGhennadi Procopciuc const struct s32cc_clk *parent; 73512e7a2cdSGhennadi Procopciuc const struct s32cc_clk *clk; 73612e7a2cdSGhennadi Procopciuc bool valid_source = false; 73712e7a2cdSGhennadi Procopciuc struct s32cc_clkmux *mux; 73812e7a2cdSGhennadi Procopciuc uint8_t i; 73912e7a2cdSGhennadi Procopciuc 74012e7a2cdSGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 74112e7a2cdSGhennadi Procopciuc if (clk == NULL) { 74212e7a2cdSGhennadi Procopciuc return -EINVAL; 74312e7a2cdSGhennadi Procopciuc } 74412e7a2cdSGhennadi Procopciuc 74512e7a2cdSGhennadi Procopciuc parent = s32cc_get_arch_clk(parent_id); 74612e7a2cdSGhennadi Procopciuc if (parent == NULL) { 74712e7a2cdSGhennadi Procopciuc return -EINVAL; 74812e7a2cdSGhennadi Procopciuc } 74912e7a2cdSGhennadi Procopciuc 75012e7a2cdSGhennadi Procopciuc if (!is_s32cc_clk_mux(clk)) { 75112e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a mux\n", id); 75212e7a2cdSGhennadi Procopciuc return -EINVAL; 75312e7a2cdSGhennadi Procopciuc } 75412e7a2cdSGhennadi Procopciuc 75512e7a2cdSGhennadi Procopciuc mux = s32cc_clk2mux(clk); 75612e7a2cdSGhennadi Procopciuc if (mux == NULL) { 75712e7a2cdSGhennadi Procopciuc ERROR("Failed to cast clock %lu to clock mux\n", id); 75812e7a2cdSGhennadi Procopciuc return -EINVAL; 75912e7a2cdSGhennadi Procopciuc } 76012e7a2cdSGhennadi Procopciuc 76112e7a2cdSGhennadi Procopciuc for (i = 0; i < mux->nclks; i++) { 76212e7a2cdSGhennadi Procopciuc if (mux->clkids[i] == parent_id) { 76312e7a2cdSGhennadi Procopciuc valid_source = true; 76412e7a2cdSGhennadi Procopciuc break; 76512e7a2cdSGhennadi Procopciuc } 76612e7a2cdSGhennadi Procopciuc } 76712e7a2cdSGhennadi Procopciuc 76812e7a2cdSGhennadi Procopciuc if (!valid_source) { 76912e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a valid clock for mux %lu\n", 77012e7a2cdSGhennadi Procopciuc parent_id, id); 77112e7a2cdSGhennadi Procopciuc return -EINVAL; 77212e7a2cdSGhennadi Procopciuc } 77312e7a2cdSGhennadi Procopciuc 77412e7a2cdSGhennadi Procopciuc mux->source_id = parent_id; 77512e7a2cdSGhennadi Procopciuc 77612e7a2cdSGhennadi Procopciuc return 0; 7773a580e9eSGhennadi Procopciuc } 7783a580e9eSGhennadi Procopciuc 7793a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void) 7803a580e9eSGhennadi Procopciuc { 7813a580e9eSGhennadi Procopciuc static const struct clk_ops s32cc_clk_ops = { 7823a580e9eSGhennadi Procopciuc .enable = s32cc_clk_enable, 7833a580e9eSGhennadi Procopciuc .disable = s32cc_clk_disable, 7843a580e9eSGhennadi Procopciuc .is_enabled = s32cc_clk_is_enabled, 7853a580e9eSGhennadi Procopciuc .get_rate = s32cc_clk_get_rate, 7863a580e9eSGhennadi Procopciuc .set_rate = s32cc_clk_set_rate, 7873a580e9eSGhennadi Procopciuc .get_parent = s32cc_clk_get_parent, 7883a580e9eSGhennadi Procopciuc .set_parent = s32cc_clk_set_parent, 7893a580e9eSGhennadi Procopciuc }; 7903a580e9eSGhennadi Procopciuc 7913a580e9eSGhennadi Procopciuc clk_register(&s32cc_clk_ops); 7923a580e9eSGhennadi Procopciuc } 7933a580e9eSGhennadi Procopciuc 794