18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2019 Microchip Technology Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 88c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 98c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/clk/at91_pmc.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "pmc.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0) 188c2ecf20Sopenharmony_ci#define PMC_PLL_CTRL1_MUL_MSK GENMASK(31, 24) 198c2ecf20Sopenharmony_ci#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1) 228c2ecf20Sopenharmony_ci#define UPLL_DIV 2 238c2ecf20Sopenharmony_ci#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define FCORE_MIN (600000000) 268c2ecf20Sopenharmony_ci#define FCORE_MAX (1200000000) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define PLL_MAX_ID 7 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct sam9x60_pll_core { 318c2ecf20Sopenharmony_ci struct regmap *regmap; 328c2ecf20Sopenharmony_ci spinlock_t *lock; 338c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics; 348c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout; 358c2ecf20Sopenharmony_ci struct clk_hw hw; 368c2ecf20Sopenharmony_ci u8 id; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct sam9x60_frac { 408c2ecf20Sopenharmony_ci struct sam9x60_pll_core core; 418c2ecf20Sopenharmony_ci u32 frac; 428c2ecf20Sopenharmony_ci u16 mul; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct sam9x60_div { 468c2ecf20Sopenharmony_ci struct sam9x60_pll_core core; 478c2ecf20Sopenharmony_ci u8 div; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define to_sam9x60_pll_core(hw) container_of(hw, struct sam9x60_pll_core, hw) 518c2ecf20Sopenharmony_ci#define to_sam9x60_frac(core) container_of(core, struct sam9x60_frac, core) 528c2ecf20Sopenharmony_ci#define to_sam9x60_div(core) container_of(core, struct sam9x60_div, core) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline bool sam9x60_pll_ready(struct regmap *regmap, int id) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci unsigned int status; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_PLL_ISR0, &status); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return !!(status & BIT(id)); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic bool sam9x60_frac_pll_ready(struct regmap *regmap, u8 id) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return sam9x60_pll_ready(regmap, id); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw, 698c2ecf20Sopenharmony_ci unsigned long parent_rate) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 728c2ecf20Sopenharmony_ci struct sam9x60_frac *frac = to_sam9x60_frac(core); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return parent_rate * (frac->mul + 1) + 758c2ecf20Sopenharmony_ci DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22)); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int sam9x60_frac_pll_prepare(struct clk_hw *hw) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 818c2ecf20Sopenharmony_ci struct sam9x60_frac *frac = to_sam9x60_frac(core); 828c2ecf20Sopenharmony_ci struct regmap *regmap = core->regmap; 838c2ecf20Sopenharmony_ci unsigned int val, cfrac, cmul; 848c2ecf20Sopenharmony_ci unsigned long flags; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci spin_lock_irqsave(core->lock, flags); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 898c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, core->id); 908c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val); 918c2ecf20Sopenharmony_ci cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift; 928c2ecf20Sopenharmony_ci cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (sam9x60_frac_pll_ready(regmap, core->id) && 958c2ecf20Sopenharmony_ci (cmul == frac->mul && cfrac == frac->frac)) 968c2ecf20Sopenharmony_ci goto unlock; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* Recommended value for PMC_PLL_ACR */ 998c2ecf20Sopenharmony_ci if (core->characteristics->upll) 1008c2ecf20Sopenharmony_ci val = AT91_PMC_PLL_ACR_DEFAULT_UPLL; 1018c2ecf20Sopenharmony_ci else 1028c2ecf20Sopenharmony_ci val = AT91_PMC_PLL_ACR_DEFAULT_PLLA; 1038c2ecf20Sopenharmony_ci regmap_write(regmap, AT91_PMC_PLL_ACR, val); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci regmap_write(regmap, AT91_PMC_PLL_CTRL1, 1068c2ecf20Sopenharmony_ci (frac->mul << core->layout->mul_shift) | 1078c2ecf20Sopenharmony_ci (frac->frac << core->layout->frac_shift)); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (core->characteristics->upll) { 1108c2ecf20Sopenharmony_ci /* Enable the UTMI internal bandgap */ 1118c2ecf20Sopenharmony_ci val |= AT91_PMC_PLL_ACR_UTMIBG; 1128c2ecf20Sopenharmony_ci regmap_write(regmap, AT91_PMC_PLL_ACR, val); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci udelay(10); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* Enable the UTMI internal regulator */ 1178c2ecf20Sopenharmony_ci val |= AT91_PMC_PLL_ACR_UTMIVR; 1188c2ecf20Sopenharmony_ci regmap_write(regmap, AT91_PMC_PLL_ACR, val); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci udelay(10); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 1248c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, 1258c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | core->id); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, 1288c2ecf20Sopenharmony_ci AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL, 1298c2ecf20Sopenharmony_ci AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 1328c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, 1338c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | core->id); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci while (!sam9x60_pll_ready(regmap, core->id)) 1368c2ecf20Sopenharmony_ci cpu_relax(); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciunlock: 1398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(core->lock, flags); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void sam9x60_frac_pll_unprepare(struct clk_hw *hw) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 1478c2ecf20Sopenharmony_ci struct regmap *regmap = core->regmap; 1488c2ecf20Sopenharmony_ci unsigned long flags; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci spin_lock_irqsave(core->lock, flags); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 1538c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, core->id); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, AT91_PMC_PLL_CTRL0_ENPLL, 0); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (core->characteristics->upll) 1588c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_ACR, 1598c2ecf20Sopenharmony_ci AT91_PMC_PLL_ACR_UTMIBG | AT91_PMC_PLL_ACR_UTMIVR, 0); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 1628c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, 1638c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | core->id); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(core->lock, flags); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int sam9x60_frac_pll_is_prepared(struct clk_hw *hw) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return sam9x60_pll_ready(core->regmap, core->id); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic long sam9x60_frac_pll_compute_mul_frac(struct sam9x60_pll_core *core, 1768c2ecf20Sopenharmony_ci unsigned long rate, 1778c2ecf20Sopenharmony_ci unsigned long parent_rate, 1788c2ecf20Sopenharmony_ci bool update) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct sam9x60_frac *frac = to_sam9x60_frac(core); 1818c2ecf20Sopenharmony_ci unsigned long tmprate, remainder; 1828c2ecf20Sopenharmony_ci unsigned long nmul = 0; 1838c2ecf20Sopenharmony_ci unsigned long nfrac = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (rate < FCORE_MIN || rate > FCORE_MAX) 1868c2ecf20Sopenharmony_ci return -ERANGE; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * Calculate the multiplier associated with the current 1908c2ecf20Sopenharmony_ci * divider that provide the closest rate to the requested one. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci nmul = mult_frac(rate, 1, parent_rate); 1938c2ecf20Sopenharmony_ci tmprate = mult_frac(parent_rate, nmul, 1); 1948c2ecf20Sopenharmony_ci remainder = rate - tmprate; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (remainder) { 1978c2ecf20Sopenharmony_ci nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22), 1988c2ecf20Sopenharmony_ci parent_rate); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate, 2018c2ecf20Sopenharmony_ci (1 << 22)); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Check if resulted rate is a valid. */ 2058c2ecf20Sopenharmony_ci if (tmprate < FCORE_MIN || tmprate > FCORE_MAX) 2068c2ecf20Sopenharmony_ci return -ERANGE; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (update) { 2098c2ecf20Sopenharmony_ci frac->mul = nmul - 1; 2108c2ecf20Sopenharmony_ci frac->frac = nfrac; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return tmprate; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic long sam9x60_frac_pll_round_rate(struct clk_hw *hw, unsigned long rate, 2178c2ecf20Sopenharmony_ci unsigned long *parent_rate) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return sam9x60_frac_pll_compute_mul_frac(core, rate, *parent_rate, false); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int sam9x60_frac_pll_set_rate(struct clk_hw *hw, unsigned long rate, 2258c2ecf20Sopenharmony_ci unsigned long parent_rate) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return sam9x60_frac_pll_compute_mul_frac(core, rate, parent_rate, true); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const struct clk_ops sam9x60_frac_pll_ops = { 2338c2ecf20Sopenharmony_ci .prepare = sam9x60_frac_pll_prepare, 2348c2ecf20Sopenharmony_ci .unprepare = sam9x60_frac_pll_unprepare, 2358c2ecf20Sopenharmony_ci .is_prepared = sam9x60_frac_pll_is_prepared, 2368c2ecf20Sopenharmony_ci .recalc_rate = sam9x60_frac_pll_recalc_rate, 2378c2ecf20Sopenharmony_ci .round_rate = sam9x60_frac_pll_round_rate, 2388c2ecf20Sopenharmony_ci .set_rate = sam9x60_frac_pll_set_rate, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int sam9x60_div_pll_prepare(struct clk_hw *hw) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 2448c2ecf20Sopenharmony_ci struct sam9x60_div *div = to_sam9x60_div(core); 2458c2ecf20Sopenharmony_ci struct regmap *regmap = core->regmap; 2468c2ecf20Sopenharmony_ci unsigned long flags; 2478c2ecf20Sopenharmony_ci unsigned int val, cdiv; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci spin_lock_irqsave(core->lock, flags); 2508c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 2518c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, core->id); 2528c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); 2538c2ecf20Sopenharmony_ci cdiv = (val & core->layout->div_mask) >> core->layout->div_shift; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Stop if enabled an nothing changed. */ 2568c2ecf20Sopenharmony_ci if (!!(val & core->layout->endiv_mask) && cdiv == div->div) 2578c2ecf20Sopenharmony_ci goto unlock; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, 2608c2ecf20Sopenharmony_ci core->layout->div_mask | core->layout->endiv_mask, 2618c2ecf20Sopenharmony_ci (div->div << core->layout->div_shift) | 2628c2ecf20Sopenharmony_ci (1 << core->layout->endiv_shift)); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 2658c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, 2668c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | core->id); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci while (!sam9x60_pll_ready(regmap, core->id)) 2698c2ecf20Sopenharmony_ci cpu_relax(); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciunlock: 2728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(core->lock, flags); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void sam9x60_div_pll_unprepare(struct clk_hw *hw) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 2808c2ecf20Sopenharmony_ci struct regmap *regmap = core->regmap; 2818c2ecf20Sopenharmony_ci unsigned long flags; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci spin_lock_irqsave(core->lock, flags); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 2868c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, core->id); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0, 2898c2ecf20Sopenharmony_ci core->layout->endiv_mask, 0); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 2928c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK, 2938c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_UPDATE | core->id); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(core->lock, flags); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int sam9x60_div_pll_is_prepared(struct clk_hw *hw) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 3018c2ecf20Sopenharmony_ci struct regmap *regmap = core->regmap; 3028c2ecf20Sopenharmony_ci unsigned long flags; 3038c2ecf20Sopenharmony_ci unsigned int val; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci spin_lock_irqsave(core->lock, flags); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 3088c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, core->id); 3098c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(core->lock, flags); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return !!(val & core->layout->endiv_mask); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic unsigned long sam9x60_div_pll_recalc_rate(struct clk_hw *hw, 3178c2ecf20Sopenharmony_ci unsigned long parent_rate) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 3208c2ecf20Sopenharmony_ci struct sam9x60_div *div = to_sam9x60_div(core); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST_ULL(parent_rate, (div->div + 1)); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic long sam9x60_div_pll_compute_div(struct sam9x60_pll_core *core, 3268c2ecf20Sopenharmony_ci unsigned long *parent_rate, 3278c2ecf20Sopenharmony_ci unsigned long rate) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics = 3308c2ecf20Sopenharmony_ci core->characteristics; 3318c2ecf20Sopenharmony_ci struct clk_hw *parent = clk_hw_get_parent(&core->hw); 3328c2ecf20Sopenharmony_ci unsigned long tmp_rate, tmp_parent_rate, tmp_diff; 3338c2ecf20Sopenharmony_ci long best_diff = -1, best_rate = -EINVAL; 3348c2ecf20Sopenharmony_ci u32 divid; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (!rate) 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (rate < characteristics->output[0].min || 3408c2ecf20Sopenharmony_ci rate > characteristics->output[0].max) 3418c2ecf20Sopenharmony_ci return -ERANGE; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for (divid = 1; divid < core->layout->div_mask; divid++) { 3448c2ecf20Sopenharmony_ci tmp_parent_rate = clk_hw_round_rate(parent, rate * divid); 3458c2ecf20Sopenharmony_ci if (!tmp_parent_rate) 3468c2ecf20Sopenharmony_ci continue; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci tmp_rate = DIV_ROUND_CLOSEST_ULL(tmp_parent_rate, divid); 3498c2ecf20Sopenharmony_ci tmp_diff = abs(rate - tmp_rate); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (best_diff < 0 || best_diff > tmp_diff) { 3528c2ecf20Sopenharmony_ci *parent_rate = tmp_parent_rate; 3538c2ecf20Sopenharmony_ci best_rate = tmp_rate; 3548c2ecf20Sopenharmony_ci best_diff = tmp_diff; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (!best_diff) 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (best_rate < characteristics->output[0].min || 3628c2ecf20Sopenharmony_ci best_rate > characteristics->output[0].max) 3638c2ecf20Sopenharmony_ci return -ERANGE; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return best_rate; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic long sam9x60_div_pll_round_rate(struct clk_hw *hw, unsigned long rate, 3698c2ecf20Sopenharmony_ci unsigned long *parent_rate) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return sam9x60_div_pll_compute_div(core, parent_rate, rate); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int sam9x60_div_pll_set_rate(struct clk_hw *hw, unsigned long rate, 3778c2ecf20Sopenharmony_ci unsigned long parent_rate) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw); 3808c2ecf20Sopenharmony_ci struct sam9x60_div *div = to_sam9x60_div(core); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci div->div = DIV_ROUND_CLOSEST(parent_rate, rate) - 1; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic const struct clk_ops sam9x60_div_pll_ops = { 3888c2ecf20Sopenharmony_ci .prepare = sam9x60_div_pll_prepare, 3898c2ecf20Sopenharmony_ci .unprepare = sam9x60_div_pll_unprepare, 3908c2ecf20Sopenharmony_ci .is_prepared = sam9x60_div_pll_is_prepared, 3918c2ecf20Sopenharmony_ci .recalc_rate = sam9x60_div_pll_recalc_rate, 3928c2ecf20Sopenharmony_ci .round_rate = sam9x60_div_pll_round_rate, 3938c2ecf20Sopenharmony_ci .set_rate = sam9x60_div_pll_set_rate, 3948c2ecf20Sopenharmony_ci}; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistruct clk_hw * __init 3978c2ecf20Sopenharmony_cisam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, 3988c2ecf20Sopenharmony_ci const char *name, const char *parent_name, 3998c2ecf20Sopenharmony_ci struct clk_hw *parent_hw, u8 id, 4008c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics, 4018c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout, bool critical) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct sam9x60_frac *frac; 4048c2ecf20Sopenharmony_ci struct clk_hw *hw; 4058c2ecf20Sopenharmony_ci struct clk_init_data init; 4068c2ecf20Sopenharmony_ci unsigned long parent_rate, flags; 4078c2ecf20Sopenharmony_ci unsigned int val; 4088c2ecf20Sopenharmony_ci int ret; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (id > PLL_MAX_ID || !lock || !parent_hw) 4118c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci frac = kzalloc(sizeof(*frac), GFP_KERNEL); 4148c2ecf20Sopenharmony_ci if (!frac) 4158c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci init.name = name; 4188c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 4198c2ecf20Sopenharmony_ci init.num_parents = 1; 4208c2ecf20Sopenharmony_ci init.ops = &sam9x60_frac_pll_ops; 4218c2ecf20Sopenharmony_ci init.flags = CLK_SET_RATE_GATE; 4228c2ecf20Sopenharmony_ci if (critical) 4238c2ecf20Sopenharmony_ci init.flags |= CLK_IS_CRITICAL; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci frac->core.id = id; 4268c2ecf20Sopenharmony_ci frac->core.hw.init = &init; 4278c2ecf20Sopenharmony_ci frac->core.characteristics = characteristics; 4288c2ecf20Sopenharmony_ci frac->core.layout = layout; 4298c2ecf20Sopenharmony_ci frac->core.regmap = regmap; 4308c2ecf20Sopenharmony_ci frac->core.lock = lock; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci spin_lock_irqsave(frac->core.lock, flags); 4338c2ecf20Sopenharmony_ci if (sam9x60_pll_ready(regmap, id)) { 4348c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 4358c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, id); 4368c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_PLL_CTRL1, &val); 4378c2ecf20Sopenharmony_ci frac->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val); 4388c2ecf20Sopenharmony_ci frac->frac = FIELD_GET(PMC_PLL_CTRL1_FRACR_MSK, val); 4398c2ecf20Sopenharmony_ci } else { 4408c2ecf20Sopenharmony_ci /* 4418c2ecf20Sopenharmony_ci * This means the PLL is not setup by bootloaders. In this 4428c2ecf20Sopenharmony_ci * case we need to set the minimum rate for it. Otherwise 4438c2ecf20Sopenharmony_ci * a clock child of this PLL may be enabled before setting 4448c2ecf20Sopenharmony_ci * its rate leading to enabling this PLL with unsupported 4458c2ecf20Sopenharmony_ci * rate. This will lead to PLL not being locked at all. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ci parent_rate = clk_hw_get_rate(parent_hw); 4488c2ecf20Sopenharmony_ci if (!parent_rate) { 4498c2ecf20Sopenharmony_ci hw = ERR_PTR(-EINVAL); 4508c2ecf20Sopenharmony_ci goto free; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, FCORE_MIN, 4548c2ecf20Sopenharmony_ci parent_rate, true); 4558c2ecf20Sopenharmony_ci if (ret < 0) { 4568c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 4578c2ecf20Sopenharmony_ci goto free; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(frac->core.lock, flags); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci hw = &frac->core.hw; 4638c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 4648c2ecf20Sopenharmony_ci if (ret) { 4658c2ecf20Sopenharmony_ci kfree(frac); 4668c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return hw; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cifree: 4728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(frac->core.lock, flags); 4738c2ecf20Sopenharmony_ci kfree(frac); 4748c2ecf20Sopenharmony_ci return hw; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistruct clk_hw * __init 4788c2ecf20Sopenharmony_cisam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock, 4798c2ecf20Sopenharmony_ci const char *name, const char *parent_name, u8 id, 4808c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics, 4818c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout, bool critical) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct sam9x60_div *div; 4848c2ecf20Sopenharmony_ci struct clk_hw *hw; 4858c2ecf20Sopenharmony_ci struct clk_init_data init; 4868c2ecf20Sopenharmony_ci unsigned long flags; 4878c2ecf20Sopenharmony_ci unsigned int val; 4888c2ecf20Sopenharmony_ci int ret; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (id > PLL_MAX_ID || !lock) 4918c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci div = kzalloc(sizeof(*div), GFP_KERNEL); 4948c2ecf20Sopenharmony_ci if (!div) 4958c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci init.name = name; 4988c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 4998c2ecf20Sopenharmony_ci init.num_parents = 1; 5008c2ecf20Sopenharmony_ci init.ops = &sam9x60_div_pll_ops; 5018c2ecf20Sopenharmony_ci init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | 5028c2ecf20Sopenharmony_ci CLK_SET_RATE_PARENT; 5038c2ecf20Sopenharmony_ci if (critical) 5048c2ecf20Sopenharmony_ci init.flags |= CLK_IS_CRITICAL; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci div->core.id = id; 5078c2ecf20Sopenharmony_ci div->core.hw.init = &init; 5088c2ecf20Sopenharmony_ci div->core.characteristics = characteristics; 5098c2ecf20Sopenharmony_ci div->core.layout = layout; 5108c2ecf20Sopenharmony_ci div->core.regmap = regmap; 5118c2ecf20Sopenharmony_ci div->core.lock = lock; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci spin_lock_irqsave(div->core.lock, flags); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, 5168c2ecf20Sopenharmony_ci AT91_PMC_PLL_UPDT_ID_MSK, id); 5178c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val); 5188c2ecf20Sopenharmony_ci div->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(div->core.lock, flags); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci hw = &div->core.hw; 5238c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 5248c2ecf20Sopenharmony_ci if (ret) { 5258c2ecf20Sopenharmony_ci kfree(div); 5268c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return hw; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 532