18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014 MediaTek Inc. 48c2ecf20Sopenharmony_ci * Author: James Liao <jamesjj.liao@mediatek.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/of_address.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "clk-mtk.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define REG_CON0 0 178c2ecf20Sopenharmony_ci#define REG_CON1 4 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define CON0_BASE_EN BIT(0) 208c2ecf20Sopenharmony_ci#define CON0_PWR_ON BIT(0) 218c2ecf20Sopenharmony_ci#define CON0_ISO_EN BIT(1) 228c2ecf20Sopenharmony_ci#define PCW_CHG_MASK BIT(31) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define AUDPLL_TUNER_EN BIT(31) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define POSTDIV_MASK 0x7 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* default 7 bits integer, can be overridden with pcwibits. */ 298c2ecf20Sopenharmony_ci#define INTEGER_BITS 7 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * MediaTek PLLs are configured through their pcw value. The pcw value describes 338c2ecf20Sopenharmony_ci * a divider in the PLL feedback loop which consists of 7 bits for the integer 348c2ecf20Sopenharmony_ci * part and the remaining bits (if present) for the fractional part. Also they 358c2ecf20Sopenharmony_ci * have a 3 bit power-of-two post divider. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct mtk_clk_pll { 398c2ecf20Sopenharmony_ci struct clk_hw hw; 408c2ecf20Sopenharmony_ci void __iomem *base_addr; 418c2ecf20Sopenharmony_ci void __iomem *pd_addr; 428c2ecf20Sopenharmony_ci void __iomem *pwr_addr; 438c2ecf20Sopenharmony_ci void __iomem *tuner_addr; 448c2ecf20Sopenharmony_ci void __iomem *tuner_en_addr; 458c2ecf20Sopenharmony_ci void __iomem *pcw_addr; 468c2ecf20Sopenharmony_ci void __iomem *pcw_chg_addr; 478c2ecf20Sopenharmony_ci const struct mtk_pll_data *data; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return container_of(hw, struct mtk_clk_pll, hw); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int mtk_pll_is_prepared(struct clk_hw *hw) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, 638c2ecf20Sopenharmony_ci u32 pcw, int postdiv) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int pcwbits = pll->data->pcwbits; 668c2ecf20Sopenharmony_ci int pcwfbits = 0; 678c2ecf20Sopenharmony_ci int ibits; 688c2ecf20Sopenharmony_ci u64 vco; 698c2ecf20Sopenharmony_ci u8 c = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* The fractional part of the PLL divider. */ 728c2ecf20Sopenharmony_ci ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS; 738c2ecf20Sopenharmony_ci if (pcwbits > ibits) 748c2ecf20Sopenharmony_ci pcwfbits = pcwbits - ibits; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci vco = (u64)fin * pcw; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0))) 798c2ecf20Sopenharmony_ci c = 1; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci vco >>= pcwfbits; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (c) 848c2ecf20Sopenharmony_ci vco++; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return ((unsigned long)vco + postdiv - 1) / postdiv; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void __mtk_pll_tuner_enable(struct mtk_clk_pll *pll) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci u32 r; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (pll->tuner_en_addr) { 948c2ecf20Sopenharmony_ci r = readl(pll->tuner_en_addr) | BIT(pll->data->tuner_en_bit); 958c2ecf20Sopenharmony_ci writel(r, pll->tuner_en_addr); 968c2ecf20Sopenharmony_ci } else if (pll->tuner_addr) { 978c2ecf20Sopenharmony_ci r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN; 988c2ecf20Sopenharmony_ci writel(r, pll->tuner_addr); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic void __mtk_pll_tuner_disable(struct mtk_clk_pll *pll) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci u32 r; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (pll->tuner_en_addr) { 1078c2ecf20Sopenharmony_ci r = readl(pll->tuner_en_addr) & ~BIT(pll->data->tuner_en_bit); 1088c2ecf20Sopenharmony_ci writel(r, pll->tuner_en_addr); 1098c2ecf20Sopenharmony_ci } else if (pll->tuner_addr) { 1108c2ecf20Sopenharmony_ci r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN; 1118c2ecf20Sopenharmony_ci writel(r, pll->tuner_addr); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, 1168c2ecf20Sopenharmony_ci int postdiv) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci u32 chg, val; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* disable tuner */ 1218c2ecf20Sopenharmony_ci __mtk_pll_tuner_disable(pll); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* set postdiv */ 1248c2ecf20Sopenharmony_ci val = readl(pll->pd_addr); 1258c2ecf20Sopenharmony_ci val &= ~(POSTDIV_MASK << pll->data->pd_shift); 1268c2ecf20Sopenharmony_ci val |= (ffs(postdiv) - 1) << pll->data->pd_shift; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* postdiv and pcw need to set at the same time if on same register */ 1298c2ecf20Sopenharmony_ci if (pll->pd_addr != pll->pcw_addr) { 1308c2ecf20Sopenharmony_ci writel(val, pll->pd_addr); 1318c2ecf20Sopenharmony_ci val = readl(pll->pcw_addr); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* set pcw */ 1358c2ecf20Sopenharmony_ci val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1, 1368c2ecf20Sopenharmony_ci pll->data->pcw_shift); 1378c2ecf20Sopenharmony_ci val |= pcw << pll->data->pcw_shift; 1388c2ecf20Sopenharmony_ci writel(val, pll->pcw_addr); 1398c2ecf20Sopenharmony_ci chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; 1408c2ecf20Sopenharmony_ci writel(chg, pll->pcw_chg_addr); 1418c2ecf20Sopenharmony_ci if (pll->tuner_addr) 1428c2ecf20Sopenharmony_ci writel(val + 1, pll->tuner_addr); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* restore tuner_en */ 1458c2ecf20Sopenharmony_ci __mtk_pll_tuner_enable(pll); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci udelay(20); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* 1518c2ecf20Sopenharmony_ci * mtk_pll_calc_values - calculate good values for a given input frequency. 1528c2ecf20Sopenharmony_ci * @pll: The pll 1538c2ecf20Sopenharmony_ci * @pcw: The pcw value (output) 1548c2ecf20Sopenharmony_ci * @postdiv: The post divider (output) 1558c2ecf20Sopenharmony_ci * @freq: The desired target frequency 1568c2ecf20Sopenharmony_ci * @fin: The input frequency 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_cistatic void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, 1608c2ecf20Sopenharmony_ci u32 freq, u32 fin) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci unsigned long fmin = pll->data->fmin ? pll->data->fmin : (1000 * MHZ); 1638c2ecf20Sopenharmony_ci const struct mtk_pll_div_table *div_table = pll->data->div_table; 1648c2ecf20Sopenharmony_ci u64 _pcw; 1658c2ecf20Sopenharmony_ci int ibits; 1668c2ecf20Sopenharmony_ci u32 val; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (freq > pll->data->fmax) 1698c2ecf20Sopenharmony_ci freq = pll->data->fmax; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (div_table) { 1728c2ecf20Sopenharmony_ci if (freq > div_table[0].freq) 1738c2ecf20Sopenharmony_ci freq = div_table[0].freq; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci for (val = 0; div_table[val + 1].freq != 0; val++) { 1768c2ecf20Sopenharmony_ci if (freq > div_table[val + 1].freq) 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci *postdiv = 1 << val; 1808c2ecf20Sopenharmony_ci } else { 1818c2ecf20Sopenharmony_ci for (val = 0; val < 5; val++) { 1828c2ecf20Sopenharmony_ci *postdiv = 1 << val; 1838c2ecf20Sopenharmony_ci if ((u64)freq * *postdiv >= fmin) 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* _pcw = freq * postdiv / fin * 2^pcwfbits */ 1898c2ecf20Sopenharmony_ci ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS; 1908c2ecf20Sopenharmony_ci _pcw = ((u64)freq << val) << (pll->data->pcwbits - ibits); 1918c2ecf20Sopenharmony_ci do_div(_pcw, fin); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci *pcw = (u32)_pcw; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 1978c2ecf20Sopenharmony_ci unsigned long parent_rate) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); 2008c2ecf20Sopenharmony_ci u32 pcw = 0; 2018c2ecf20Sopenharmony_ci u32 postdiv; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate); 2048c2ecf20Sopenharmony_ci mtk_pll_set_rate_regs(pll, pcw, postdiv); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic unsigned long mtk_pll_recalc_rate(struct clk_hw *hw, 2108c2ecf20Sopenharmony_ci unsigned long parent_rate) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); 2138c2ecf20Sopenharmony_ci u32 postdiv; 2148c2ecf20Sopenharmony_ci u32 pcw; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK; 2178c2ecf20Sopenharmony_ci postdiv = 1 << postdiv; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift; 2208c2ecf20Sopenharmony_ci pcw &= GENMASK(pll->data->pcwbits - 1, 0); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate, 2268c2ecf20Sopenharmony_ci unsigned long *prate) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); 2298c2ecf20Sopenharmony_ci u32 pcw = 0; 2308c2ecf20Sopenharmony_ci int postdiv; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int mtk_pll_prepare(struct clk_hw *hw) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); 2408c2ecf20Sopenharmony_ci u32 r; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci r = readl(pll->pwr_addr) | CON0_PWR_ON; 2438c2ecf20Sopenharmony_ci writel(r, pll->pwr_addr); 2448c2ecf20Sopenharmony_ci udelay(1); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci r = readl(pll->pwr_addr) & ~CON0_ISO_EN; 2478c2ecf20Sopenharmony_ci writel(r, pll->pwr_addr); 2488c2ecf20Sopenharmony_ci udelay(1); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci r = readl(pll->base_addr + REG_CON0); 2518c2ecf20Sopenharmony_ci r |= pll->data->en_mask; 2528c2ecf20Sopenharmony_ci writel(r, pll->base_addr + REG_CON0); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci __mtk_pll_tuner_enable(pll); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci udelay(20); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (pll->data->flags & HAVE_RST_BAR) { 2598c2ecf20Sopenharmony_ci r = readl(pll->base_addr + REG_CON0); 2608c2ecf20Sopenharmony_ci r |= pll->data->rst_bar_mask; 2618c2ecf20Sopenharmony_ci writel(r, pll->base_addr + REG_CON0); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void mtk_pll_unprepare(struct clk_hw *hw) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); 2708c2ecf20Sopenharmony_ci u32 r; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (pll->data->flags & HAVE_RST_BAR) { 2738c2ecf20Sopenharmony_ci r = readl(pll->base_addr + REG_CON0); 2748c2ecf20Sopenharmony_ci r &= ~pll->data->rst_bar_mask; 2758c2ecf20Sopenharmony_ci writel(r, pll->base_addr + REG_CON0); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci __mtk_pll_tuner_disable(pll); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci r = readl(pll->base_addr + REG_CON0); 2818c2ecf20Sopenharmony_ci r &= ~CON0_BASE_EN; 2828c2ecf20Sopenharmony_ci writel(r, pll->base_addr + REG_CON0); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci r = readl(pll->pwr_addr) | CON0_ISO_EN; 2858c2ecf20Sopenharmony_ci writel(r, pll->pwr_addr); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci r = readl(pll->pwr_addr) & ~CON0_PWR_ON; 2888c2ecf20Sopenharmony_ci writel(r, pll->pwr_addr); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic const struct clk_ops mtk_pll_ops = { 2928c2ecf20Sopenharmony_ci .is_prepared = mtk_pll_is_prepared, 2938c2ecf20Sopenharmony_ci .prepare = mtk_pll_prepare, 2948c2ecf20Sopenharmony_ci .unprepare = mtk_pll_unprepare, 2958c2ecf20Sopenharmony_ci .recalc_rate = mtk_pll_recalc_rate, 2968c2ecf20Sopenharmony_ci .round_rate = mtk_pll_round_rate, 2978c2ecf20Sopenharmony_ci .set_rate = mtk_pll_set_rate, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, 3018c2ecf20Sopenharmony_ci void __iomem *base) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct mtk_clk_pll *pll; 3048c2ecf20Sopenharmony_ci struct clk_init_data init = {}; 3058c2ecf20Sopenharmony_ci struct clk *clk; 3068c2ecf20Sopenharmony_ci const char *parent_name = "clk26m"; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 3098c2ecf20Sopenharmony_ci if (!pll) 3108c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci pll->base_addr = base + data->reg; 3138c2ecf20Sopenharmony_ci pll->pwr_addr = base + data->pwr_reg; 3148c2ecf20Sopenharmony_ci pll->pd_addr = base + data->pd_reg; 3158c2ecf20Sopenharmony_ci pll->pcw_addr = base + data->pcw_reg; 3168c2ecf20Sopenharmony_ci if (data->pcw_chg_reg) 3178c2ecf20Sopenharmony_ci pll->pcw_chg_addr = base + data->pcw_chg_reg; 3188c2ecf20Sopenharmony_ci else 3198c2ecf20Sopenharmony_ci pll->pcw_chg_addr = pll->base_addr + REG_CON1; 3208c2ecf20Sopenharmony_ci if (data->tuner_reg) 3218c2ecf20Sopenharmony_ci pll->tuner_addr = base + data->tuner_reg; 3228c2ecf20Sopenharmony_ci if (data->tuner_en_reg) 3238c2ecf20Sopenharmony_ci pll->tuner_en_addr = base + data->tuner_en_reg; 3248c2ecf20Sopenharmony_ci pll->hw.init = &init; 3258c2ecf20Sopenharmony_ci pll->data = data; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci init.name = data->name; 3288c2ecf20Sopenharmony_ci init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; 3298c2ecf20Sopenharmony_ci init.ops = &mtk_pll_ops; 3308c2ecf20Sopenharmony_ci if (data->parent_name) 3318c2ecf20Sopenharmony_ci init.parent_names = &data->parent_name; 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 3348c2ecf20Sopenharmony_ci init.num_parents = 1; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci clk = clk_register(NULL, &pll->hw); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 3398c2ecf20Sopenharmony_ci kfree(pll); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return clk; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_civoid mtk_clk_register_plls(struct device_node *node, 3458c2ecf20Sopenharmony_ci const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci void __iomem *base; 3488c2ecf20Sopenharmony_ci int i; 3498c2ecf20Sopenharmony_ci struct clk *clk; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci base = of_iomap(node, 0); 3528c2ecf20Sopenharmony_ci if (!base) { 3538c2ecf20Sopenharmony_ci pr_err("%s(): ioremap failed\n", __func__); 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < num_plls; i++) { 3588c2ecf20Sopenharmony_ci const struct mtk_pll_data *pll = &plls[i]; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci clk = mtk_clk_register_pll(pll, base); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 3638c2ecf20Sopenharmony_ci pr_err("Failed to register clk %s: %ld\n", 3648c2ecf20Sopenharmony_ci pll->name, PTR_ERR(clk)); 3658c2ecf20Sopenharmony_ci continue; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci clk_data->clks[pll->id] = clk; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 371