18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Zynq UltraScale+ MPSoC PLL driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-2018 Xilinx 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include "clk-zynqmp.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/** 148c2ecf20Sopenharmony_ci * struct zynqmp_pll - PLL clock 158c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 168c2ecf20Sopenharmony_ci * @clk_id: PLL clock ID 178c2ecf20Sopenharmony_ci * @set_pll_mode: Whether an IOCTL_SET_PLL_FRAC_MODE request be sent to ATF 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistruct zynqmp_pll { 208c2ecf20Sopenharmony_ci struct clk_hw hw; 218c2ecf20Sopenharmony_ci u32 clk_id; 228c2ecf20Sopenharmony_ci bool set_pll_mode; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define to_zynqmp_pll(_hw) container_of(_hw, struct zynqmp_pll, hw) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define PLL_FBDIV_MIN 25 288c2ecf20Sopenharmony_ci#define PLL_FBDIV_MAX 125 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define PS_PLL_VCO_MIN 1500000000 318c2ecf20Sopenharmony_ci#define PS_PLL_VCO_MAX 3000000000UL 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cienum pll_mode { 348c2ecf20Sopenharmony_ci PLL_MODE_INT, 358c2ecf20Sopenharmony_ci PLL_MODE_FRAC, 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define FRAC_OFFSET 0x8 398c2ecf20Sopenharmony_ci#define PLLFCFG_FRAC_EN BIT(31) 408c2ecf20Sopenharmony_ci#define FRAC_DIV BIT(16) /* 2^16 */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * zynqmp_pll_get_mode() - Get mode of PLL 448c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Return: Mode of PLL 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cistatic inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 518c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 528c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 538c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 548c2ecf20Sopenharmony_ci int ret; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci ret = zynqmp_pm_get_pll_frac_mode(clk_id, ret_payload); 578c2ecf20Sopenharmony_ci if (ret) 588c2ecf20Sopenharmony_ci pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n", 598c2ecf20Sopenharmony_ci __func__, clk_name, ret); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return ret_payload[1]; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * zynqmp_pll_set_mode() - Set the PLL mode 668c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 678c2ecf20Sopenharmony_ci * @on: Flag to determine the mode 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistatic inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 728c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 738c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 748c2ecf20Sopenharmony_ci int ret; 758c2ecf20Sopenharmony_ci u32 mode; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (on) 788c2ecf20Sopenharmony_ci mode = PLL_MODE_FRAC; 798c2ecf20Sopenharmony_ci else 808c2ecf20Sopenharmony_ci mode = PLL_MODE_INT; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = zynqmp_pm_set_pll_frac_mode(clk_id, mode); 838c2ecf20Sopenharmony_ci if (ret) 848c2ecf20Sopenharmony_ci pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n", 858c2ecf20Sopenharmony_ci __func__, clk_name, ret); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci clk->set_pll_mode = true; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/** 918c2ecf20Sopenharmony_ci * zynqmp_pll_round_rate() - Round a clock frequency 928c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 938c2ecf20Sopenharmony_ci * @rate: Desired clock frequency 948c2ecf20Sopenharmony_ci * @prate: Clock frequency of parent clock 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Return: Frequency closest to @rate the hardware can generate 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate, 998c2ecf20Sopenharmony_ci unsigned long *prate) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci u32 fbdiv; 1028c2ecf20Sopenharmony_ci u32 mult, div; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Let rate fall inside the range PS_PLL_VCO_MIN ~ PS_PLL_VCO_MAX */ 1058c2ecf20Sopenharmony_ci if (rate > PS_PLL_VCO_MAX) { 1068c2ecf20Sopenharmony_ci div = DIV_ROUND_UP(rate, PS_PLL_VCO_MAX); 1078c2ecf20Sopenharmony_ci rate = rate / div; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci if (rate < PS_PLL_VCO_MIN) { 1108c2ecf20Sopenharmony_ci mult = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate); 1118c2ecf20Sopenharmony_ci rate = rate * mult; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci fbdiv = DIV_ROUND_CLOSEST(rate, *prate); 1158c2ecf20Sopenharmony_ci if (fbdiv < PLL_FBDIV_MIN || fbdiv > PLL_FBDIV_MAX) { 1168c2ecf20Sopenharmony_ci fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX); 1178c2ecf20Sopenharmony_ci rate = *prate * fbdiv; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return rate; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/** 1248c2ecf20Sopenharmony_ci * zynqmp_pll_recalc_rate() - Recalculate clock frequency 1258c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 1268c2ecf20Sopenharmony_ci * @parent_rate: Clock frequency of parent clock 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Return: Current clock frequency 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw, 1318c2ecf20Sopenharmony_ci unsigned long parent_rate) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 1348c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 1358c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 1368c2ecf20Sopenharmony_ci u32 fbdiv, data; 1378c2ecf20Sopenharmony_ci unsigned long rate, frac; 1388c2ecf20Sopenharmony_ci u32 ret_payload[PAYLOAD_ARG_CNT]; 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_getdivider(clk_id, &fbdiv); 1428c2ecf20Sopenharmony_ci if (ret) 1438c2ecf20Sopenharmony_ci pr_warn_once("%s() get divider failed for %s, ret = %d\n", 1448c2ecf20Sopenharmony_ci __func__, clk_name, ret); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci rate = parent_rate * fbdiv; 1478c2ecf20Sopenharmony_ci if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) { 1488c2ecf20Sopenharmony_ci zynqmp_pm_get_pll_frac_data(clk_id, ret_payload); 1498c2ecf20Sopenharmony_ci data = ret_payload[1]; 1508c2ecf20Sopenharmony_ci frac = (parent_rate * data) / FRAC_DIV; 1518c2ecf20Sopenharmony_ci rate = rate + frac; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return rate; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/** 1588c2ecf20Sopenharmony_ci * zynqmp_pll_set_rate() - Set rate of PLL 1598c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 1608c2ecf20Sopenharmony_ci * @rate: Frequency of clock to be set 1618c2ecf20Sopenharmony_ci * @parent_rate: Clock frequency of parent clock 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * Set PLL divider to set desired rate. 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Returns: rate which is set on success else error code 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate, 1688c2ecf20Sopenharmony_ci unsigned long parent_rate) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 1718c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 1728c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 1738c2ecf20Sopenharmony_ci u32 fbdiv; 1748c2ecf20Sopenharmony_ci long rate_div, frac, m, f; 1758c2ecf20Sopenharmony_ci int ret; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci rate_div = (rate * FRAC_DIV) / parent_rate; 1788c2ecf20Sopenharmony_ci f = rate_div % FRAC_DIV; 1798c2ecf20Sopenharmony_ci zynqmp_pll_set_mode(hw, !!f); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (f) { 1828c2ecf20Sopenharmony_ci m = rate_div / FRAC_DIV; 1838c2ecf20Sopenharmony_ci m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX)); 1848c2ecf20Sopenharmony_ci rate = parent_rate * m; 1858c2ecf20Sopenharmony_ci frac = (parent_rate * f) / FRAC_DIV; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_setdivider(clk_id, m); 1888c2ecf20Sopenharmony_ci if (ret == -EUSERS) 1898c2ecf20Sopenharmony_ci WARN(1, "More than allowed devices are using the %s, which is forbidden\n", 1908c2ecf20Sopenharmony_ci clk_name); 1918c2ecf20Sopenharmony_ci else if (ret) 1928c2ecf20Sopenharmony_ci pr_warn_once("%s() set divider failed for %s, ret = %d\n", 1938c2ecf20Sopenharmony_ci __func__, clk_name, ret); 1948c2ecf20Sopenharmony_ci zynqmp_pm_set_pll_frac_data(clk_id, f); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return rate + frac; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate); 2008c2ecf20Sopenharmony_ci fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX); 2018c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_setdivider(clk_id, fbdiv); 2028c2ecf20Sopenharmony_ci if (ret) 2038c2ecf20Sopenharmony_ci pr_warn_once("%s() set divider failed for %s, ret = %d\n", 2048c2ecf20Sopenharmony_ci __func__, clk_name, ret); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return parent_rate * fbdiv; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/** 2108c2ecf20Sopenharmony_ci * zynqmp_pll_is_enabled() - Check if a clock is enabled 2118c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Return: 1 if the clock is enabled, 0 otherwise 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_cistatic int zynqmp_pll_is_enabled(struct clk_hw *hw) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 2188c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 2198c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 2208c2ecf20Sopenharmony_ci unsigned int state; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_getstate(clk_id, &state); 2248c2ecf20Sopenharmony_ci if (ret) { 2258c2ecf20Sopenharmony_ci pr_warn_once("%s() clock get state failed for %s, ret = %d\n", 2268c2ecf20Sopenharmony_ci __func__, clk_name, ret); 2278c2ecf20Sopenharmony_ci return -EIO; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return state ? 1 : 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * zynqmp_pll_enable() - Enable clock 2358c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Return: 0 on success else error code 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic int zynqmp_pll_enable(struct clk_hw *hw) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 2428c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 2438c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 2448c2ecf20Sopenharmony_ci int ret; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Don't skip enabling clock if there is an IOCTL_SET_PLL_FRAC_MODE request 2488c2ecf20Sopenharmony_ci * that has been sent to ATF. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci if (zynqmp_pll_is_enabled(hw) && (!clk->set_pll_mode)) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci clk->set_pll_mode = false; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_enable(clk_id); 2568c2ecf20Sopenharmony_ci if (ret) 2578c2ecf20Sopenharmony_ci pr_warn_once("%s() clock enable failed for %s, ret = %d\n", 2588c2ecf20Sopenharmony_ci __func__, clk_name, ret); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * zynqmp_pll_disable() - Disable clock 2658c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_cistatic void zynqmp_pll_disable(struct clk_hw *hw) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct zynqmp_pll *clk = to_zynqmp_pll(hw); 2708c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 2718c2ecf20Sopenharmony_ci u32 clk_id = clk->clk_id; 2728c2ecf20Sopenharmony_ci int ret; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!zynqmp_pll_is_enabled(hw)) 2758c2ecf20Sopenharmony_ci return; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci ret = zynqmp_pm_clock_disable(clk_id); 2788c2ecf20Sopenharmony_ci if (ret) 2798c2ecf20Sopenharmony_ci pr_warn_once("%s() clock disable failed for %s, ret = %d\n", 2808c2ecf20Sopenharmony_ci __func__, clk_name, ret); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic const struct clk_ops zynqmp_pll_ops = { 2848c2ecf20Sopenharmony_ci .enable = zynqmp_pll_enable, 2858c2ecf20Sopenharmony_ci .disable = zynqmp_pll_disable, 2868c2ecf20Sopenharmony_ci .is_enabled = zynqmp_pll_is_enabled, 2878c2ecf20Sopenharmony_ci .round_rate = zynqmp_pll_round_rate, 2888c2ecf20Sopenharmony_ci .recalc_rate = zynqmp_pll_recalc_rate, 2898c2ecf20Sopenharmony_ci .set_rate = zynqmp_pll_set_rate, 2908c2ecf20Sopenharmony_ci}; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/** 2938c2ecf20Sopenharmony_ci * zynqmp_clk_register_pll() - Register PLL with the clock framework 2948c2ecf20Sopenharmony_ci * @name: PLL name 2958c2ecf20Sopenharmony_ci * @clk_id: Clock ID 2968c2ecf20Sopenharmony_ci * @parents: Name of this clock's parents 2978c2ecf20Sopenharmony_ci * @num_parents: Number of parents 2988c2ecf20Sopenharmony_ci * @nodes: Clock topology node 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Return: clock hardware to the registered clock 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistruct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id, 3038c2ecf20Sopenharmony_ci const char * const *parents, 3048c2ecf20Sopenharmony_ci u8 num_parents, 3058c2ecf20Sopenharmony_ci const struct clock_topology *nodes) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct zynqmp_pll *pll; 3088c2ecf20Sopenharmony_ci struct clk_hw *hw; 3098c2ecf20Sopenharmony_ci struct clk_init_data init; 3108c2ecf20Sopenharmony_ci int ret; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci init.name = name; 3138c2ecf20Sopenharmony_ci init.ops = &zynqmp_pll_ops; 3148c2ecf20Sopenharmony_ci init.flags = nodes->flag; 3158c2ecf20Sopenharmony_ci init.parent_names = parents; 3168c2ecf20Sopenharmony_ci init.num_parents = 1; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 3198c2ecf20Sopenharmony_ci if (!pll) 3208c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci pll->hw.init = &init; 3238c2ecf20Sopenharmony_ci pll->clk_id = clk_id; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci hw = &pll->hw; 3268c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 3278c2ecf20Sopenharmony_ci if (ret) { 3288c2ecf20Sopenharmony_ci kfree(pll); 3298c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci clk_hw_set_rate_range(hw, PS_PLL_VCO_MIN, PS_PLL_VCO_MAX); 3338c2ecf20Sopenharmony_ci if (ret < 0) 3348c2ecf20Sopenharmony_ci pr_err("%s:ERROR clk_set_rate_range failed %d\n", name, ret); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return hw; 3378c2ecf20Sopenharmony_ci} 338