122f65a38SJerome Brunet // SPDX-License-Identifier: GPL-2.0 27a29a869SCarlo Caione /* 37a29a869SCarlo Caione * Copyright (c) 2015 Endless Mobile, Inc. 47a29a869SCarlo Caione * Author: Carlo Caione <carlo@endlessm.com> 57a29a869SCarlo Caione * 68289aafaSJerome Brunet * Copyright (c) 2018 Baylibre, SAS. 78289aafaSJerome Brunet * Author: Jerome Brunet <jbrunet@baylibre.com> 87a29a869SCarlo Caione */ 97a29a869SCarlo Caione 107a29a869SCarlo Caione /* 117a29a869SCarlo Caione * In the most basic form, a Meson PLL is composed as follows: 127a29a869SCarlo Caione * 137a29a869SCarlo Caione * PLL 1487173557SJerome Brunet * +--------------------------------+ 157a29a869SCarlo Caione * | | 1687173557SJerome Brunet * | +--+ | 1787173557SJerome Brunet * in >>-----[ /N ]--->| | +-----+ | 1887173557SJerome Brunet * | | |------| DCO |---->> out 1987173557SJerome Brunet * | +--------->| | +--v--+ | 2087173557SJerome Brunet * | | +--+ | | 2187173557SJerome Brunet * | | | | 2287173557SJerome Brunet * | +--[ *(M + (F/Fmax) ]<--+ | 237a29a869SCarlo Caione * | | 2487173557SJerome Brunet * +--------------------------------+ 257a29a869SCarlo Caione * 2687173557SJerome Brunet * out = in * (m + frac / frac_max) / n 277a29a869SCarlo Caione */ 287a29a869SCarlo Caione 297a29a869SCarlo Caione #include <linux/clk-provider.h> 307a29a869SCarlo Caione #include <linux/delay.h> 317a29a869SCarlo Caione #include <linux/err.h> 327a29a869SCarlo Caione #include <linux/io.h> 3394aa8a41SJerome Brunet #include <linux/math64.h> 347a29a869SCarlo Caione #include <linux/module.h> 358eed1db1SJerome Brunet #include <linux/rational.h> 367a29a869SCarlo Caione 37889c2b7eSJerome Brunet #include "clk-regmap.h" 38889c2b7eSJerome Brunet #include "clk-pll.h" 397a29a869SCarlo Caione 40722825dcSJerome Brunet static inline struct meson_clk_pll_data * 41722825dcSJerome Brunet meson_clk_pll_data(struct clk_regmap *clk) 42722825dcSJerome Brunet { 43722825dcSJerome Brunet return (struct meson_clk_pll_data *)clk->data; 44722825dcSJerome Brunet } 457a29a869SCarlo Caione 468eed1db1SJerome Brunet static int __pll_round_closest_mult(struct meson_clk_pll_data *pll) 478eed1db1SJerome Brunet { 488eed1db1SJerome Brunet if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) && 498eed1db1SJerome Brunet !MESON_PARM_APPLICABLE(&pll->frac)) 508eed1db1SJerome Brunet return 1; 518eed1db1SJerome Brunet 528eed1db1SJerome Brunet return 0; 538eed1db1SJerome Brunet } 548eed1db1SJerome Brunet 558289aafaSJerome Brunet static unsigned long __pll_params_to_rate(unsigned long parent_rate, 568eed1db1SJerome Brunet unsigned int m, unsigned int n, 578eed1db1SJerome Brunet unsigned int frac, 588289aafaSJerome Brunet struct meson_clk_pll_data *pll) 598289aafaSJerome Brunet { 608eed1db1SJerome Brunet u64 rate = (u64)parent_rate * m; 618289aafaSJerome Brunet 628289aafaSJerome Brunet if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { 638289aafaSJerome Brunet u64 frac_rate = (u64)parent_rate * frac; 648289aafaSJerome Brunet 658289aafaSJerome Brunet rate += DIV_ROUND_UP_ULL(frac_rate, 668289aafaSJerome Brunet (1 << pll->frac.width)); 678289aafaSJerome Brunet } 688289aafaSJerome Brunet 698eed1db1SJerome Brunet return DIV_ROUND_UP_ULL(rate, n); 708289aafaSJerome Brunet } 718289aafaSJerome Brunet 727a29a869SCarlo Caione static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, 737a29a869SCarlo Caione unsigned long parent_rate) 747a29a869SCarlo Caione { 75722825dcSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 76722825dcSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 778eed1db1SJerome Brunet unsigned int m, n, frac; 787a29a869SCarlo Caione 798eed1db1SJerome Brunet n = meson_parm_read(clk->map, &pll->n); 808eed1db1SJerome Brunet m = meson_parm_read(clk->map, &pll->m); 817d3142e5SJerome Brunet 828289aafaSJerome Brunet frac = MESON_PARM_APPLICABLE(&pll->frac) ? 838289aafaSJerome Brunet meson_parm_read(clk->map, &pll->frac) : 848289aafaSJerome Brunet 0; 8594aa8a41SJerome Brunet 868eed1db1SJerome Brunet return __pll_params_to_rate(parent_rate, m, n, frac, pll); 8794aa8a41SJerome Brunet } 8894aa8a41SJerome Brunet 898eed1db1SJerome Brunet static unsigned int __pll_params_with_frac(unsigned long rate, 908289aafaSJerome Brunet unsigned long parent_rate, 918eed1db1SJerome Brunet unsigned int m, 928eed1db1SJerome Brunet unsigned int n, 938289aafaSJerome Brunet struct meson_clk_pll_data *pll) 948289aafaSJerome Brunet { 958eed1db1SJerome Brunet unsigned int frac_max = (1 << pll->frac.width); 968eed1db1SJerome Brunet u64 val = (u64)rate * n; 978eed1db1SJerome Brunet 988eed1db1SJerome Brunet /* Bail out if we are already over the requested rate */ 998eed1db1SJerome Brunet if (rate < parent_rate * m / n) 1008eed1db1SJerome Brunet return 0; 1018289aafaSJerome Brunet 1020a1be867SJerome Brunet if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) 1030a1be867SJerome Brunet val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); 1040a1be867SJerome Brunet else 1058289aafaSJerome Brunet val = div_u64(val * frac_max, parent_rate); 1060a1be867SJerome Brunet 1078eed1db1SJerome Brunet val -= m * frac_max; 1088289aafaSJerome Brunet 1098eed1db1SJerome Brunet return min((unsigned int)val, (frac_max - 1)); 1108289aafaSJerome Brunet } 1118289aafaSJerome Brunet 112dd601dbcSJerome Brunet static bool meson_clk_pll_is_better(unsigned long rate, 113dd601dbcSJerome Brunet unsigned long best, 114dd601dbcSJerome Brunet unsigned long now, 1158289aafaSJerome Brunet struct meson_clk_pll_data *pll) 1168289aafaSJerome Brunet { 1178eed1db1SJerome Brunet if (__pll_round_closest_mult(pll)) { 118dd601dbcSJerome Brunet /* Round Closest */ 119dd601dbcSJerome Brunet if (abs(now - rate) < abs(best - rate)) 120dd601dbcSJerome Brunet return true; 1218eed1db1SJerome Brunet } else { 1228eed1db1SJerome Brunet /* Round down */ 123*d6f987c8SMartin Blumenstingl if (now <= rate && best < now) 1248eed1db1SJerome Brunet return true; 125dd601dbcSJerome Brunet } 126dd601dbcSJerome Brunet 127dd601dbcSJerome Brunet return false; 128dd601dbcSJerome Brunet } 129dd601dbcSJerome Brunet 1308eed1db1SJerome Brunet static int meson_clk_get_pll_table_index(unsigned int index, 1318eed1db1SJerome Brunet unsigned int *m, 1328eed1db1SJerome Brunet unsigned int *n, 133dd601dbcSJerome Brunet struct meson_clk_pll_data *pll) 134dd601dbcSJerome Brunet { 1358eed1db1SJerome Brunet if (!pll->table[index].n) 1368eed1db1SJerome Brunet return -EINVAL; 1378eed1db1SJerome Brunet 1388eed1db1SJerome Brunet *m = pll->table[index].m; 1398eed1db1SJerome Brunet *n = pll->table[index].n; 1408eed1db1SJerome Brunet 1418eed1db1SJerome Brunet return 0; 1428eed1db1SJerome Brunet } 1438eed1db1SJerome Brunet 1448eed1db1SJerome Brunet static unsigned int meson_clk_get_pll_range_m(unsigned long rate, 1458eed1db1SJerome Brunet unsigned long parent_rate, 1468eed1db1SJerome Brunet unsigned int n, 1478eed1db1SJerome Brunet struct meson_clk_pll_data *pll) 1488eed1db1SJerome Brunet { 1498eed1db1SJerome Brunet u64 val = (u64)rate * n; 1508eed1db1SJerome Brunet 1518eed1db1SJerome Brunet if (__pll_round_closest_mult(pll)) 1528eed1db1SJerome Brunet return DIV_ROUND_CLOSEST_ULL(val, parent_rate); 1538eed1db1SJerome Brunet 1548eed1db1SJerome Brunet return div_u64(val, parent_rate); 1558eed1db1SJerome Brunet } 1568eed1db1SJerome Brunet 1578eed1db1SJerome Brunet static int meson_clk_get_pll_range_index(unsigned long rate, 1588eed1db1SJerome Brunet unsigned long parent_rate, 1598eed1db1SJerome Brunet unsigned int index, 1608eed1db1SJerome Brunet unsigned int *m, 1618eed1db1SJerome Brunet unsigned int *n, 1628eed1db1SJerome Brunet struct meson_clk_pll_data *pll) 1638eed1db1SJerome Brunet { 1648eed1db1SJerome Brunet *n = index + 1; 1658eed1db1SJerome Brunet 1668eed1db1SJerome Brunet /* Check the predivider range */ 1678eed1db1SJerome Brunet if (*n >= (1 << pll->n.width)) 1688eed1db1SJerome Brunet return -EINVAL; 1698eed1db1SJerome Brunet 1708eed1db1SJerome Brunet if (*n == 1) { 1718eed1db1SJerome Brunet /* Get the boundaries out the way */ 1728eed1db1SJerome Brunet if (rate <= pll->range->min * parent_rate) { 1738eed1db1SJerome Brunet *m = pll->range->min; 1748eed1db1SJerome Brunet return -ENODATA; 1758eed1db1SJerome Brunet } else if (rate >= pll->range->max * parent_rate) { 1768eed1db1SJerome Brunet *m = pll->range->max; 1778eed1db1SJerome Brunet return -ENODATA; 1788eed1db1SJerome Brunet } 1798eed1db1SJerome Brunet } 1808eed1db1SJerome Brunet 1818eed1db1SJerome Brunet *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll); 1828eed1db1SJerome Brunet 1838eed1db1SJerome Brunet /* the pre-divider gives a multiplier too big - stop */ 1848eed1db1SJerome Brunet if (*m >= (1 << pll->m.width)) 1858eed1db1SJerome Brunet return -EINVAL; 1868eed1db1SJerome Brunet 1878eed1db1SJerome Brunet return 0; 1888eed1db1SJerome Brunet } 1898eed1db1SJerome Brunet 1908eed1db1SJerome Brunet static int meson_clk_get_pll_get_index(unsigned long rate, 1918eed1db1SJerome Brunet unsigned long parent_rate, 1928eed1db1SJerome Brunet unsigned int index, 1938eed1db1SJerome Brunet unsigned int *m, 1948eed1db1SJerome Brunet unsigned int *n, 1958eed1db1SJerome Brunet struct meson_clk_pll_data *pll) 1968eed1db1SJerome Brunet { 1978eed1db1SJerome Brunet if (pll->range) 1988eed1db1SJerome Brunet return meson_clk_get_pll_range_index(rate, parent_rate, 1998eed1db1SJerome Brunet index, m, n, pll); 2008eed1db1SJerome Brunet else if (pll->table) 2018eed1db1SJerome Brunet return meson_clk_get_pll_table_index(index, m, n, pll); 2028eed1db1SJerome Brunet 2038eed1db1SJerome Brunet return -EINVAL; 2048eed1db1SJerome Brunet } 2058eed1db1SJerome Brunet 2068eed1db1SJerome Brunet static int meson_clk_get_pll_settings(unsigned long rate, 2078eed1db1SJerome Brunet unsigned long parent_rate, 2088eed1db1SJerome Brunet unsigned int *best_m, 2098eed1db1SJerome Brunet unsigned int *best_n, 2108eed1db1SJerome Brunet struct meson_clk_pll_data *pll) 2118eed1db1SJerome Brunet { 212dd601dbcSJerome Brunet unsigned long best = 0, now = 0; 2138eed1db1SJerome Brunet unsigned int i, m, n; 2148eed1db1SJerome Brunet int ret; 2158289aafaSJerome Brunet 2168eed1db1SJerome Brunet for (i = 0, ret = 0; !ret; i++) { 2178eed1db1SJerome Brunet ret = meson_clk_get_pll_get_index(rate, parent_rate, 2188eed1db1SJerome Brunet i, &m, &n, pll); 2198eed1db1SJerome Brunet if (ret == -EINVAL) 2208eed1db1SJerome Brunet break; 2218289aafaSJerome Brunet 2228eed1db1SJerome Brunet now = __pll_params_to_rate(parent_rate, m, n, 0, pll); 2238eed1db1SJerome Brunet if (meson_clk_pll_is_better(rate, best, now, pll)) { 224dd601dbcSJerome Brunet best = now; 2258eed1db1SJerome Brunet *best_m = m; 2268eed1db1SJerome Brunet *best_n = n; 2278eed1db1SJerome Brunet 2288eed1db1SJerome Brunet if (now == rate) 2298eed1db1SJerome Brunet break; 230dd601dbcSJerome Brunet } 2310a1be867SJerome Brunet } 2328289aafaSJerome Brunet 2338eed1db1SJerome Brunet return best ? 0 : -EINVAL; 2347a29a869SCarlo Caione } 2357a29a869SCarlo Caione 2367a29a869SCarlo Caione static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, 2377a29a869SCarlo Caione unsigned long *parent_rate) 2387a29a869SCarlo Caione { 239722825dcSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 240722825dcSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 2418eed1db1SJerome Brunet unsigned int m, n, frac; 242dd601dbcSJerome Brunet unsigned long round; 2438eed1db1SJerome Brunet int ret; 2447a29a869SCarlo Caione 2458eed1db1SJerome Brunet ret = meson_clk_get_pll_settings(rate, *parent_rate, &m, &n, pll); 2468eed1db1SJerome Brunet if (ret) 247840e1a73SJerome Brunet return meson_clk_pll_recalc_rate(hw, *parent_rate); 248840e1a73SJerome Brunet 2498eed1db1SJerome Brunet round = __pll_params_to_rate(*parent_rate, m, n, 0, pll); 250dd601dbcSJerome Brunet 251dd601dbcSJerome Brunet if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round) 252dd601dbcSJerome Brunet return round; 2537a29a869SCarlo Caione 2548289aafaSJerome Brunet /* 2558289aafaSJerome Brunet * The rate provided by the setting is not an exact match, let's 2568289aafaSJerome Brunet * try to improve the result using the fractional parameter 2578289aafaSJerome Brunet */ 2588eed1db1SJerome Brunet frac = __pll_params_with_frac(rate, *parent_rate, m, n, pll); 2597a29a869SCarlo Caione 2608eed1db1SJerome Brunet return __pll_params_to_rate(*parent_rate, m, n, frac, pll); 2617a29a869SCarlo Caione } 2627a29a869SCarlo Caione 263722825dcSJerome Brunet static int meson_clk_pll_wait_lock(struct clk_hw *hw) 264722825dcSJerome Brunet { 265722825dcSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 266722825dcSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 267c178b003SJerome Brunet int delay = 24000000; 268722825dcSJerome Brunet 269722825dcSJerome Brunet do { 270722825dcSJerome Brunet /* Is the clock locked now ? */ 271722825dcSJerome Brunet if (meson_parm_read(clk->map, &pll->l)) 272722825dcSJerome Brunet return 0; 273722825dcSJerome Brunet 274722825dcSJerome Brunet delay--; 275722825dcSJerome Brunet } while (delay > 0); 276722825dcSJerome Brunet 27745fcbec7SNeil Armstrong return -ETIMEDOUT; 27845fcbec7SNeil Armstrong } 27945fcbec7SNeil Armstrong 280722825dcSJerome Brunet static void meson_clk_pll_init(struct clk_hw *hw) 2817a29a869SCarlo Caione { 282722825dcSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 283722825dcSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 2847a29a869SCarlo Caione 285722825dcSJerome Brunet if (pll->init_count) { 286722825dcSJerome Brunet meson_parm_write(clk->map, &pll->rst, 1); 287722825dcSJerome Brunet regmap_multi_reg_write(clk->map, pll->init_regs, 288722825dcSJerome Brunet pll->init_count); 289722825dcSJerome Brunet meson_parm_write(clk->map, &pll->rst, 0); 2907a29a869SCarlo Caione } 29145fcbec7SNeil Armstrong } 29245fcbec7SNeil Armstrong 293d6e81845SMartin Blumenstingl static int meson_clk_pll_is_enabled(struct clk_hw *hw) 294d6e81845SMartin Blumenstingl { 295d6e81845SMartin Blumenstingl struct clk_regmap *clk = to_clk_regmap(hw); 296d6e81845SMartin Blumenstingl struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 297d6e81845SMartin Blumenstingl 298d6e81845SMartin Blumenstingl if (meson_parm_read(clk->map, &pll->rst) || 299d6e81845SMartin Blumenstingl !meson_parm_read(clk->map, &pll->en) || 300d6e81845SMartin Blumenstingl !meson_parm_read(clk->map, &pll->l)) 301d6e81845SMartin Blumenstingl return 0; 302d6e81845SMartin Blumenstingl 303d6e81845SMartin Blumenstingl return 1; 304d6e81845SMartin Blumenstingl } 305d6e81845SMartin Blumenstingl 306e40c7e3cSJerome Brunet static int meson_clk_pll_enable(struct clk_hw *hw) 307e40c7e3cSJerome Brunet { 308e40c7e3cSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 309e40c7e3cSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 310e40c7e3cSJerome Brunet 311d6e81845SMartin Blumenstingl /* do nothing if the PLL is already enabled */ 312d6e81845SMartin Blumenstingl if (clk_hw_is_enabled(hw)) 313d6e81845SMartin Blumenstingl return 0; 314d6e81845SMartin Blumenstingl 315e40c7e3cSJerome Brunet /* Make sure the pll is in reset */ 316e40c7e3cSJerome Brunet meson_parm_write(clk->map, &pll->rst, 1); 317e40c7e3cSJerome Brunet 318e40c7e3cSJerome Brunet /* Enable the pll */ 319e40c7e3cSJerome Brunet meson_parm_write(clk->map, &pll->en, 1); 320e40c7e3cSJerome Brunet 321e40c7e3cSJerome Brunet /* Take the pll out reset */ 322e40c7e3cSJerome Brunet meson_parm_write(clk->map, &pll->rst, 0); 323e40c7e3cSJerome Brunet 324e40c7e3cSJerome Brunet if (meson_clk_pll_wait_lock(hw)) 325e40c7e3cSJerome Brunet return -EIO; 326e40c7e3cSJerome Brunet 327e40c7e3cSJerome Brunet return 0; 328e40c7e3cSJerome Brunet } 329e40c7e3cSJerome Brunet 330e40c7e3cSJerome Brunet static void meson_clk_pll_disable(struct clk_hw *hw) 331e40c7e3cSJerome Brunet { 332e40c7e3cSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 333e40c7e3cSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 334e40c7e3cSJerome Brunet 335e40c7e3cSJerome Brunet /* Put the pll is in reset */ 336e40c7e3cSJerome Brunet meson_parm_write(clk->map, &pll->rst, 1); 337e40c7e3cSJerome Brunet 338e40c7e3cSJerome Brunet /* Disable the pll */ 339e40c7e3cSJerome Brunet meson_parm_write(clk->map, &pll->en, 0); 340e40c7e3cSJerome Brunet } 341e40c7e3cSJerome Brunet 3427a29a869SCarlo Caione static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 3437a29a869SCarlo Caione unsigned long parent_rate) 3447a29a869SCarlo Caione { 345722825dcSJerome Brunet struct clk_regmap *clk = to_clk_regmap(hw); 346722825dcSJerome Brunet struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 3478eed1db1SJerome Brunet unsigned int enabled, m, n, frac = 0, ret; 3487a29a869SCarlo Caione unsigned long old_rate; 3497a29a869SCarlo Caione 3507a29a869SCarlo Caione if (parent_rate == 0 || rate == 0) 3517a29a869SCarlo Caione return -EINVAL; 3527a29a869SCarlo Caione 3537a29a869SCarlo Caione old_rate = rate; 3547a29a869SCarlo Caione 3558eed1db1SJerome Brunet ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll); 3568eed1db1SJerome Brunet if (ret) 3578eed1db1SJerome Brunet return ret; 3587a29a869SCarlo Caione 359e40c7e3cSJerome Brunet enabled = meson_parm_read(clk->map, &pll->en); 360e40c7e3cSJerome Brunet if (enabled) 361e40c7e3cSJerome Brunet meson_clk_pll_disable(hw); 36245fcbec7SNeil Armstrong 3638eed1db1SJerome Brunet meson_parm_write(clk->map, &pll->n, n); 3648eed1db1SJerome Brunet meson_parm_write(clk->map, &pll->m, m); 3657a29a869SCarlo Caione 3668289aafaSJerome Brunet if (MESON_PARM_APPLICABLE(&pll->frac)) { 3678eed1db1SJerome Brunet frac = __pll_params_with_frac(rate, parent_rate, m, n, pll); 3688289aafaSJerome Brunet meson_parm_write(clk->map, &pll->frac, frac); 3698289aafaSJerome Brunet } 3707a29a869SCarlo Caione 371e40c7e3cSJerome Brunet /* If the pll is stopped, bail out now */ 372e40c7e3cSJerome Brunet if (!enabled) 373e40c7e3cSJerome Brunet return 0; 3744a472951SMichael Turquette 375e40c7e3cSJerome Brunet if (meson_clk_pll_enable(hw)) { 3767a29a869SCarlo Caione pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", 3777a29a869SCarlo Caione __func__, old_rate); 378722825dcSJerome Brunet /* 379722825dcSJerome Brunet * FIXME: Do we really need/want this HACK ? 380722825dcSJerome Brunet * It looks unsafe. what happens if the clock gets into a 381722825dcSJerome Brunet * broken state and we can't lock back on the old_rate ? Looks 382722825dcSJerome Brunet * like an infinite recursion is possible 383722825dcSJerome Brunet */ 3847a29a869SCarlo Caione meson_clk_pll_set_rate(hw, old_rate, parent_rate); 3857a29a869SCarlo Caione } 3867a29a869SCarlo Caione 387722825dcSJerome Brunet return 0; 3887a29a869SCarlo Caione } 3897a29a869SCarlo Caione 390ec623f2aSMichael Turquette const struct clk_ops meson_clk_pll_ops = { 391722825dcSJerome Brunet .init = meson_clk_pll_init, 3927a29a869SCarlo Caione .recalc_rate = meson_clk_pll_recalc_rate, 3937a29a869SCarlo Caione .round_rate = meson_clk_pll_round_rate, 3947a29a869SCarlo Caione .set_rate = meson_clk_pll_set_rate, 395d6e81845SMartin Blumenstingl .is_enabled = meson_clk_pll_is_enabled, 396e40c7e3cSJerome Brunet .enable = meson_clk_pll_enable, 397e40c7e3cSJerome Brunet .disable = meson_clk_pll_disable 3987a29a869SCarlo Caione }; 399889c2b7eSJerome Brunet EXPORT_SYMBOL_GPL(meson_clk_pll_ops); 4007a29a869SCarlo Caione 401ec623f2aSMichael Turquette const struct clk_ops meson_clk_pll_ro_ops = { 4027a29a869SCarlo Caione .recalc_rate = meson_clk_pll_recalc_rate, 403d6e81845SMartin Blumenstingl .is_enabled = meson_clk_pll_is_enabled, 4047a29a869SCarlo Caione }; 405889c2b7eSJerome Brunet EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops); 406889c2b7eSJerome Brunet 407889c2b7eSJerome Brunet MODULE_DESCRIPTION("Amlogic PLL driver"); 408889c2b7eSJerome Brunet MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>"); 409889c2b7eSJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 410889c2b7eSJerome Brunet MODULE_LICENSE("GPL v2"); 411