162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2021 NXP 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <linux/clk-provider.h> 862306a36Sopenharmony_ci#include <linux/err.h> 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/iopoll.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <asm/div64.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "clk.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define PLL_CTRL 0x0 1862306a36Sopenharmony_ci#define HW_CTRL_SEL BIT(16) 1962306a36Sopenharmony_ci#define CLKMUX_BYPASS BIT(2) 2062306a36Sopenharmony_ci#define CLKMUX_EN BIT(1) 2162306a36Sopenharmony_ci#define POWERUP_MASK BIT(0) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define PLL_ANA_PRG 0x10 2462306a36Sopenharmony_ci#define PLL_SPREAD_SPECTRUM 0x30 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define PLL_NUMERATOR 0x40 2762306a36Sopenharmony_ci#define PLL_MFN_MASK GENMASK(31, 2) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define PLL_DENOMINATOR 0x50 3062306a36Sopenharmony_ci#define PLL_MFD_MASK GENMASK(29, 0) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define PLL_DIV 0x60 3362306a36Sopenharmony_ci#define PLL_MFI_MASK GENMASK(24, 16) 3462306a36Sopenharmony_ci#define PLL_RDIV_MASK GENMASK(15, 13) 3562306a36Sopenharmony_ci#define PLL_ODIV_MASK GENMASK(7, 0) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define PLL_STATUS 0xF0 4062306a36Sopenharmony_ci#define LOCK_STATUS BIT(0) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define DFS_STATUS 0xF4 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define LOCK_TIMEOUT_US 200 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \ 4762306a36Sopenharmony_ci { \ 4862306a36Sopenharmony_ci .rate = (_rate), \ 4962306a36Sopenharmony_ci .mfi = (_mfi), \ 5062306a36Sopenharmony_ci .mfn = (_mfn), \ 5162306a36Sopenharmony_ci .mfd = (_mfd), \ 5262306a36Sopenharmony_ci .rdiv = (_rdiv), \ 5362306a36Sopenharmony_ci .odiv = (_odiv), \ 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \ 5762306a36Sopenharmony_ci { \ 5862306a36Sopenharmony_ci .rate = (_rate), \ 5962306a36Sopenharmony_ci .mfi = (_mfi), \ 6062306a36Sopenharmony_ci .mfn = 0, \ 6162306a36Sopenharmony_ci .mfd = 0, \ 6262306a36Sopenharmony_ci .rdiv = (_rdiv), \ 6362306a36Sopenharmony_ci .odiv = (_odiv), \ 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct clk_fracn_gppll { 6762306a36Sopenharmony_ci struct clk_hw hw; 6862306a36Sopenharmony_ci void __iomem *base; 6962306a36Sopenharmony_ci const struct imx_fracn_gppll_rate_table *rate_table; 7062306a36Sopenharmony_ci int rate_count; 7162306a36Sopenharmony_ci u32 flags; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Fvco = (Fref / rdiv) * (MFI + MFN / MFD) 7662306a36Sopenharmony_ci * Fout = Fvco / odiv 7762306a36Sopenharmony_ci * The (Fref / rdiv) should be in range 20MHz to 40MHz 7862306a36Sopenharmony_ci * The Fvco should be in range 2.5Ghz to 5Ghz 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic const struct imx_fracn_gppll_rate_table fracn_tbl[] = { 8162306a36Sopenharmony_ci PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), 8262306a36Sopenharmony_ci PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), 8362306a36Sopenharmony_ci PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), 8462306a36Sopenharmony_ci PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8), 8562306a36Sopenharmony_ci PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8), 8662306a36Sopenharmony_ci PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), 8762306a36Sopenharmony_ci PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), 8862306a36Sopenharmony_ci PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), 8962306a36Sopenharmony_ci PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10), 9062306a36Sopenharmony_ci PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12) 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistruct imx_fracn_gppll_clk imx_fracn_gppll = { 9462306a36Sopenharmony_ci .rate_table = fracn_tbl, 9562306a36Sopenharmony_ci .rate_count = ARRAY_SIZE(fracn_tbl), 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_fracn_gppll); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Fvco = (Fref / rdiv) * MFI 10162306a36Sopenharmony_ci * Fout = Fvco / odiv 10262306a36Sopenharmony_ci * The (Fref / rdiv) should be in range 20MHz to 40MHz 10362306a36Sopenharmony_ci * The Fvco should be in range 2.5Ghz to 5Ghz 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic const struct imx_fracn_gppll_rate_table int_tbl[] = { 10662306a36Sopenharmony_ci PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), 10762306a36Sopenharmony_ci PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), 10862306a36Sopenharmony_ci PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct imx_fracn_gppll_clk imx_fracn_gppll_integer = { 11262306a36Sopenharmony_ci .rate_table = int_tbl, 11362306a36Sopenharmony_ci .rate_count = ARRAY_SIZE(int_tbl), 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_fracn_gppll_integer); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return container_of(hw, struct clk_fracn_gppll, hw); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic const struct imx_fracn_gppll_rate_table * 12362306a36Sopenharmony_ciimx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; 12662306a36Sopenharmony_ci int i; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 12962306a36Sopenharmony_ci if (rate == rate_table[i].rate) 13062306a36Sopenharmony_ci return &rate_table[i]; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return NULL; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate, 13662306a36Sopenharmony_ci unsigned long *prate) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 13962306a36Sopenharmony_ci const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; 14062306a36Sopenharmony_ci int i; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Assuming rate_table is in descending order */ 14362306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 14462306a36Sopenharmony_ci if (rate >= rate_table[i].rate) 14562306a36Sopenharmony_ci return rate_table[i].rate; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* return minimum supported value */ 14862306a36Sopenharmony_ci return rate_table[pll->rate_count - 1].rate; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 15462306a36Sopenharmony_ci const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; 15562306a36Sopenharmony_ci u32 pll_numerator, pll_denominator, pll_div; 15662306a36Sopenharmony_ci u32 mfi, mfn, mfd, rdiv, odiv; 15762306a36Sopenharmony_ci u64 fvco = parent_rate; 15862306a36Sopenharmony_ci long rate = 0; 15962306a36Sopenharmony_ci int i; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR); 16262306a36Sopenharmony_ci mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR); 16562306a36Sopenharmony_ci mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci pll_div = readl_relaxed(pll->base + PLL_DIV); 16862306a36Sopenharmony_ci mfi = FIELD_GET(PLL_MFI_MASK, pll_div); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); 17162306a36Sopenharmony_ci odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * Sometimes, the recalculated rate has deviation due to 17562306a36Sopenharmony_ci * the frac part. So find the accurate pll rate from the table 17662306a36Sopenharmony_ci * first, if no match rate in the table, use the rate calculated 17762306a36Sopenharmony_ci * from the equation below. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) { 18062306a36Sopenharmony_ci if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi && 18162306a36Sopenharmony_ci rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv && 18262306a36Sopenharmony_ci rate_table[i].odiv == odiv) 18362306a36Sopenharmony_ci rate = rate_table[i].rate; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (rate) 18762306a36Sopenharmony_ci return (unsigned long)rate; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!rdiv) 19062306a36Sopenharmony_ci rdiv = rdiv + 1; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci switch (odiv) { 19362306a36Sopenharmony_ci case 0: 19462306a36Sopenharmony_ci odiv = 2; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci case 1: 19762306a36Sopenharmony_ci odiv = 3; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci default: 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (pll->flags & CLK_FRACN_GPPLL_INTEGER) { 20462306a36Sopenharmony_ci /* Fvco = (Fref / rdiv) * MFI */ 20562306a36Sopenharmony_ci fvco = fvco * mfi; 20662306a36Sopenharmony_ci do_div(fvco, rdiv * odiv); 20762306a36Sopenharmony_ci } else { 20862306a36Sopenharmony_ci /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */ 20962306a36Sopenharmony_ci fvco = fvco * mfi * mfd + fvco * mfn; 21062306a36Sopenharmony_ci do_div(fvco, mfd * rdiv * odiv); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return (unsigned long)fvco; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci u32 val; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return readl_poll_timeout(pll->base + PLL_STATUS, val, 22162306a36Sopenharmony_ci val & LOCK_STATUS, 0, LOCK_TIMEOUT_US); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, 22562306a36Sopenharmony_ci unsigned long prate) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 22862306a36Sopenharmony_ci const struct imx_fracn_gppll_rate_table *rate; 22962306a36Sopenharmony_ci u32 tmp, pll_div, ana_mfn; 23062306a36Sopenharmony_ci int ret; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci rate = imx_get_pll_settings(pll, drate); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Hardware control select disable. PLL is control by register */ 23562306a36Sopenharmony_ci tmp = readl_relaxed(pll->base + PLL_CTRL); 23662306a36Sopenharmony_ci tmp &= ~HW_CTRL_SEL; 23762306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + PLL_CTRL); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Disable output */ 24062306a36Sopenharmony_ci tmp = readl_relaxed(pll->base + PLL_CTRL); 24162306a36Sopenharmony_ci tmp &= ~CLKMUX_EN; 24262306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + PLL_CTRL); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Power Down */ 24562306a36Sopenharmony_ci tmp &= ~POWERUP_MASK; 24662306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + PLL_CTRL); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Disable BYPASS */ 24962306a36Sopenharmony_ci tmp &= ~CLKMUX_BYPASS; 25062306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + PLL_CTRL); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | 25362306a36Sopenharmony_ci FIELD_PREP(PLL_MFI_MASK, rate->mfi); 25462306a36Sopenharmony_ci writel_relaxed(pll_div, pll->base + PLL_DIV); 25562306a36Sopenharmony_ci if (pll->flags & CLK_FRACN_GPPLL_FRACN) { 25662306a36Sopenharmony_ci writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); 25762306a36Sopenharmony_ci writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Wait for 5us according to fracn mode pll doc */ 26162306a36Sopenharmony_ci udelay(5); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Enable Powerup */ 26462306a36Sopenharmony_ci tmp |= POWERUP_MASK; 26562306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + PLL_CTRL); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Wait Lock */ 26862306a36Sopenharmony_ci ret = clk_fracn_gppll_wait_lock(pll); 26962306a36Sopenharmony_ci if (ret) 27062306a36Sopenharmony_ci return ret; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Enable output */ 27362306a36Sopenharmony_ci tmp |= CLKMUX_EN; 27462306a36Sopenharmony_ci writel_relaxed(tmp, pll->base + PLL_CTRL); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ana_mfn = readl_relaxed(pll->base + PLL_STATUS); 27762306a36Sopenharmony_ci ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n"); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int clk_fracn_gppll_prepare(struct clk_hw *hw) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 28762306a36Sopenharmony_ci u32 val; 28862306a36Sopenharmony_ci int ret; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CTRL); 29162306a36Sopenharmony_ci if (val & POWERUP_MASK) 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci val |= CLKMUX_BYPASS; 29562306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CTRL); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci val |= POWERUP_MASK; 29862306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CTRL); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci val |= CLKMUX_EN; 30162306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CTRL); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ret = clk_fracn_gppll_wait_lock(pll); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci val &= ~CLKMUX_BYPASS; 30862306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CTRL); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int clk_fracn_gppll_is_prepared(struct clk_hw *hw) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 31662306a36Sopenharmony_ci u32 val; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CTRL); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return (val & POWERUP_MASK) ? 1 : 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void clk_fracn_gppll_unprepare(struct clk_hw *hw) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); 32662306a36Sopenharmony_ci u32 val; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CTRL); 32962306a36Sopenharmony_ci val &= ~POWERUP_MASK; 33062306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CTRL); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic const struct clk_ops clk_fracn_gppll_ops = { 33462306a36Sopenharmony_ci .prepare = clk_fracn_gppll_prepare, 33562306a36Sopenharmony_ci .unprepare = clk_fracn_gppll_unprepare, 33662306a36Sopenharmony_ci .is_prepared = clk_fracn_gppll_is_prepared, 33762306a36Sopenharmony_ci .recalc_rate = clk_fracn_gppll_recalc_rate, 33862306a36Sopenharmony_ci .round_rate = clk_fracn_gppll_round_rate, 33962306a36Sopenharmony_ci .set_rate = clk_fracn_gppll_set_rate, 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name, 34362306a36Sopenharmony_ci void __iomem *base, 34462306a36Sopenharmony_ci const struct imx_fracn_gppll_clk *pll_clk, 34562306a36Sopenharmony_ci u32 pll_flags) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct clk_fracn_gppll *pll; 34862306a36Sopenharmony_ci struct clk_hw *hw; 34962306a36Sopenharmony_ci struct clk_init_data init; 35062306a36Sopenharmony_ci int ret; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 35362306a36Sopenharmony_ci if (!pll) 35462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci init.name = name; 35762306a36Sopenharmony_ci init.flags = pll_clk->flags; 35862306a36Sopenharmony_ci init.parent_names = &parent_name; 35962306a36Sopenharmony_ci init.num_parents = 1; 36062306a36Sopenharmony_ci init.ops = &clk_fracn_gppll_ops; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci pll->base = base; 36362306a36Sopenharmony_ci pll->hw.init = &init; 36462306a36Sopenharmony_ci pll->rate_table = pll_clk->rate_table; 36562306a36Sopenharmony_ci pll->rate_count = pll_clk->rate_count; 36662306a36Sopenharmony_ci pll->flags = pll_flags; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci hw = &pll->hw; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = clk_hw_register(NULL, hw); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci pr_err("%s: failed to register pll %s %d\n", __func__, name, ret); 37362306a36Sopenharmony_ci kfree(pll); 37462306a36Sopenharmony_ci return ERR_PTR(ret); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return hw; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistruct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, 38162306a36Sopenharmony_ci const struct imx_fracn_gppll_clk *pll_clk) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistruct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, 38862306a36Sopenharmony_ci void __iomem *base, 38962306a36Sopenharmony_ci const struct imx_fracn_gppll_clk *pll_clk) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer); 394