18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell PXA25x family clocks 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Robert Jarzmik 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Heavily inspired from former arch/arm/mach-pxa/pxa25x.c. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * For non-devicetree platforms. Once pxa is fully converted to devicetree, this 108c2ecf20Sopenharmony_ci * should go away. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <mach/pxa2xx-regs.h> 188c2ecf20Sopenharmony_ci#include <mach/smemc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <dt-bindings/clock/pxa-clock.h> 218c2ecf20Sopenharmony_ci#include "clk-pxa.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define KHz 1000 248c2ecf20Sopenharmony_ci#define MHz (1000 * 1000) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cienum { 278c2ecf20Sopenharmony_ci PXA_CORE_RUN = 0, 288c2ecf20Sopenharmony_ci PXA_CORE_TURBO, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define PXA25x_CLKCFG(T) \ 328c2ecf20Sopenharmony_ci (CLKCFG_FCS | \ 338c2ecf20Sopenharmony_ci ((T) ? CLKCFG_TURBO : 0)) 348c2ecf20Sopenharmony_ci#define PXA25x_CCCR(N2, M, L) (N2 << 7 | M << 5 | L) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3) 378c2ecf20Sopenharmony_ci#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Define the refresh period in mSec for the SDRAM and the number of rows */ 408c2ecf20Sopenharmony_ci#define SDRAM_TREF 64 /* standard 64ms SDRAM */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Various clock factors driven by the CCCR register. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* Crystal Frequency to Memory Frequency Multiplier (L) */ 478c2ecf20Sopenharmony_cistatic unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Memory Frequency to Run Mode Frequency Multiplier (M) */ 508c2ecf20Sopenharmony_cistatic unsigned char M_clk_mult[4] = { 0, 1, 2, 4 }; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ 538c2ecf20Sopenharmony_ci/* Note: we store the value N * 2 here. */ 548c2ecf20Sopenharmony_cistatic unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const char * const get_freq_khz[] = { 578c2ecf20Sopenharmony_ci "core", "run", "cpll", "memory" 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int get_sdram_rows(void) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci static int sdram_rows; 638c2ecf20Sopenharmony_ci unsigned int drac2 = 0, drac0 = 0; 648c2ecf20Sopenharmony_ci u32 mdcnfg; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (sdram_rows) 678c2ecf20Sopenharmony_ci return sdram_rows; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci mdcnfg = readl_relaxed(MDCNFG); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3)) 728c2ecf20Sopenharmony_ci drac2 = MDCNFG_DRAC2(mdcnfg); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1)) 758c2ecf20Sopenharmony_ci drac0 = MDCNFG_DRAC0(mdcnfg); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci sdram_rows = 1 << (11 + max(drac0, drac2)); 788c2ecf20Sopenharmony_ci return sdram_rows; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic u32 mdrefr_dri(unsigned int freq_khz) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci u32 interval = freq_khz * SDRAM_TREF / get_sdram_rows(); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return interval / 32; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Get the clock frequency as reflected by CCCR and the turbo flag. 908c2ecf20Sopenharmony_ci * We assume these values have been applied via a fcs. 918c2ecf20Sopenharmony_ci * If info is not 0 we also display the current settings. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ciunsigned int pxa25x_get_clk_frequency_khz(int info) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct clk *clk; 968c2ecf20Sopenharmony_ci unsigned long clks[5]; 978c2ecf20Sopenharmony_ci int i; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(get_freq_khz); i++) { 1008c2ecf20Sopenharmony_ci clk = clk_get(NULL, get_freq_khz[i]); 1018c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 1028c2ecf20Sopenharmony_ci clks[i] = 0; 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci clks[i] = clk_get_rate(clk); 1058c2ecf20Sopenharmony_ci clk_put(clk); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (info) { 1108c2ecf20Sopenharmony_ci pr_info("Run Mode clock: %ld.%02ldMHz\n", 1118c2ecf20Sopenharmony_ci clks[1] / 1000000, (clks[1] % 1000000) / 10000); 1128c2ecf20Sopenharmony_ci pr_info("Turbo Mode clock: %ld.%02ldMHz\n", 1138c2ecf20Sopenharmony_ci clks[2] / 1000000, (clks[2] % 1000000) / 10000); 1148c2ecf20Sopenharmony_ci pr_info("Memory clock: %ld.%02ldMHz\n", 1158c2ecf20Sopenharmony_ci clks[3] / 1000000, (clks[3] % 1000000) / 10000); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return (unsigned int)clks[0] / KHz; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic unsigned long clk_pxa25x_memory_get_rate(struct clk_hw *hw, 1228c2ecf20Sopenharmony_ci unsigned long parent_rate) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci unsigned long cccr = readl(CCCR); 1258c2ecf20Sopenharmony_ci unsigned int m = M_clk_mult[(cccr >> 5) & 0x03]; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return parent_rate / m; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ciPARENTS(clk_pxa25x_memory) = { "run" }; 1308c2ecf20Sopenharmony_ciRATE_RO_OPS(clk_pxa25x_memory, "memory"); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciPARENTS(pxa25x_pbus95) = { "ppll_95_85mhz", "ppll_95_85mhz" }; 1338c2ecf20Sopenharmony_ciPARENTS(pxa25x_pbus147) = { "ppll_147_46mhz", "ppll_147_46mhz" }; 1348c2ecf20Sopenharmony_ciPARENTS(pxa25x_osc3) = { "osc_3_6864mhz", "osc_3_6864mhz" }; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define PXA25X_CKEN(dev_id, con_id, parents, mult, div, \ 1378c2ecf20Sopenharmony_ci bit, is_lp, flags) \ 1388c2ecf20Sopenharmony_ci PXA_CKEN(dev_id, con_id, bit, parents, mult, div, mult, div, \ 1398c2ecf20Sopenharmony_ci is_lp, CKEN, CKEN_ ## bit, flags) 1408c2ecf20Sopenharmony_ci#define PXA25X_PBUS95_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ 1418c2ecf20Sopenharmony_ci PXA25X_CKEN(dev_id, con_id, pxa25x_pbus95_parents, mult_hp, \ 1428c2ecf20Sopenharmony_ci div_hp, bit, NULL, 0) 1438c2ecf20Sopenharmony_ci#define PXA25X_PBUS147_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay)\ 1448c2ecf20Sopenharmony_ci PXA25X_CKEN(dev_id, con_id, pxa25x_pbus147_parents, mult_hp, \ 1458c2ecf20Sopenharmony_ci div_hp, bit, NULL, 0) 1468c2ecf20Sopenharmony_ci#define PXA25X_OSC3_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ 1478c2ecf20Sopenharmony_ci PXA25X_CKEN(dev_id, con_id, pxa25x_osc3_parents, mult_hp, \ 1488c2ecf20Sopenharmony_ci div_hp, bit, NULL, 0) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define PXA25X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ 1518c2ecf20Sopenharmony_ci PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ 1528c2ecf20Sopenharmony_ci CKEN, CKEN_ ## bit, 0) 1538c2ecf20Sopenharmony_ci#define PXA25X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ 1548c2ecf20Sopenharmony_ci PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ 1558c2ecf20Sopenharmony_ci CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic struct desc_clk_cken pxa25x_clocks[] __initdata = { 1588c2ecf20Sopenharmony_ci PXA25X_PBUS95_CKEN("pxa2xx-mci.0", NULL, MMC, 1, 5, 0), 1598c2ecf20Sopenharmony_ci PXA25X_PBUS95_CKEN("pxa2xx-i2c.0", NULL, I2C, 1, 3, 0), 1608c2ecf20Sopenharmony_ci PXA25X_PBUS95_CKEN("pxa2xx-ir", "FICPCLK", FICP, 1, 2, 0), 1618c2ecf20Sopenharmony_ci PXA25X_PBUS95_CKEN("pxa25x-udc", NULL, USB, 1, 2, 5), 1628c2ecf20Sopenharmony_ci PXA25X_PBUS147_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 10, 1), 1638c2ecf20Sopenharmony_ci PXA25X_PBUS147_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 10, 1), 1648c2ecf20Sopenharmony_ci PXA25X_PBUS147_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 10, 1), 1658c2ecf20Sopenharmony_ci PXA25X_PBUS147_CKEN("pxa2xx-uart.3", NULL, HWUART, 1, 10, 1), 1668c2ecf20Sopenharmony_ci PXA25X_PBUS147_CKEN("pxa2xx-i2s", NULL, I2S, 1, 10, 0), 1678c2ecf20Sopenharmony_ci PXA25X_PBUS147_CKEN(NULL, "AC97CLK", AC97, 1, 12, 0), 1688c2ecf20Sopenharmony_ci PXA25X_OSC3_CKEN("pxa25x-ssp.0", NULL, SSP, 1, 1, 0), 1698c2ecf20Sopenharmony_ci PXA25X_OSC3_CKEN("pxa25x-nssp.1", NULL, NSSP, 1, 1, 0), 1708c2ecf20Sopenharmony_ci PXA25X_OSC3_CKEN("pxa25x-nssp.2", NULL, ASSP, 1, 1, 0), 1718c2ecf20Sopenharmony_ci PXA25X_OSC3_CKEN("pxa25x-pwm.0", NULL, PWM0, 1, 1, 0), 1728c2ecf20Sopenharmony_ci PXA25X_OSC3_CKEN("pxa25x-pwm.1", NULL, PWM1, 1, 1, 0), 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci PXA25X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, clk_pxa25x_memory_parents, 0), 1758c2ecf20Sopenharmony_ci PXA25X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, 1768c2ecf20Sopenharmony_ci clk_pxa25x_memory_parents, 0), 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * In this table, PXA25x_CCCR(N2, M, L) has the following meaning, where : 1818c2ecf20Sopenharmony_ci * - freq_cpll = n * m * L * 3.6864 MHz 1828c2ecf20Sopenharmony_ci * - n = N2 / 2 1838c2ecf20Sopenharmony_ci * - m = 2^(M - 1), where 1 <= M <= 3 1848c2ecf20Sopenharmony_ci * - l = L_clk_mult[L], ie. { 0, 27, 32, 36, 40, 45, 0, }[L] 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic struct pxa2xx_freq pxa25x_freqs[] = { 1878c2ecf20Sopenharmony_ci /* CPU MEMBUS CCCR DIV2 CCLKCFG */ 1888c2ecf20Sopenharmony_ci { 99532800, 99500, PXA25x_CCCR(2, 1, 1), 1, PXA25x_CLKCFG(1)}, 1898c2ecf20Sopenharmony_ci {199065600, 99500, PXA25x_CCCR(4, 1, 1), 0, PXA25x_CLKCFG(1)}, 1908c2ecf20Sopenharmony_ci {298598400, 99500, PXA25x_CCCR(3, 2, 1), 0, PXA25x_CLKCFG(1)}, 1918c2ecf20Sopenharmony_ci {398131200, 99500, PXA25x_CCCR(4, 2, 1), 0, PXA25x_CLKCFG(1)}, 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic u8 clk_pxa25x_core_get_parent(struct clk_hw *hw) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci unsigned long clkcfg; 1978c2ecf20Sopenharmony_ci unsigned int t; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); 2008c2ecf20Sopenharmony_ci t = clkcfg & (1 << 0); 2018c2ecf20Sopenharmony_ci if (t) 2028c2ecf20Sopenharmony_ci return PXA_CORE_TURBO; 2038c2ecf20Sopenharmony_ci return PXA_CORE_RUN; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int clk_pxa25x_core_set_parent(struct clk_hw *hw, u8 index) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci if (index > PXA_CORE_TURBO) 2098c2ecf20Sopenharmony_ci return -EINVAL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci pxa2xx_core_turbo_switch(index == PXA_CORE_TURBO); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int clk_pxa25x_core_determine_rate(struct clk_hw *hw, 2178c2ecf20Sopenharmony_ci struct clk_rate_request *req) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci return __clk_mux_determine_rate(hw, req); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ciPARENTS(clk_pxa25x_core) = { "run", "cpll" }; 2238c2ecf20Sopenharmony_ciMUX_OPS(clk_pxa25x_core, "core", CLK_SET_RATE_PARENT); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic unsigned long clk_pxa25x_run_get_rate(struct clk_hw *hw, 2268c2ecf20Sopenharmony_ci unsigned long parent_rate) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci unsigned long cccr = readl(CCCR); 2298c2ecf20Sopenharmony_ci unsigned int n2 = N2_clk_mult[(cccr >> 7) & 0x07]; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return (parent_rate / n2) * 2; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ciPARENTS(clk_pxa25x_run) = { "cpll" }; 2348c2ecf20Sopenharmony_ciRATE_RO_OPS(clk_pxa25x_run, "run"); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic unsigned long clk_pxa25x_cpll_get_rate(struct clk_hw *hw, 2378c2ecf20Sopenharmony_ci unsigned long parent_rate) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci unsigned long clkcfg, cccr = readl(CCCR); 2408c2ecf20Sopenharmony_ci unsigned int l, m, n2, t; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); 2438c2ecf20Sopenharmony_ci t = clkcfg & (1 << 0); 2448c2ecf20Sopenharmony_ci l = L_clk_mult[(cccr >> 0) & 0x1f]; 2458c2ecf20Sopenharmony_ci m = M_clk_mult[(cccr >> 5) & 0x03]; 2468c2ecf20Sopenharmony_ci n2 = N2_clk_mult[(cccr >> 7) & 0x07]; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return m * l * n2 * parent_rate / 2; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int clk_pxa25x_cpll_determine_rate(struct clk_hw *hw, 2528c2ecf20Sopenharmony_ci struct clk_rate_request *req) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci return pxa2xx_determine_rate(req, pxa25x_freqs, 2558c2ecf20Sopenharmony_ci ARRAY_SIZE(pxa25x_freqs)); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int clk_pxa25x_cpll_set_rate(struct clk_hw *hw, unsigned long rate, 2598c2ecf20Sopenharmony_ci unsigned long parent_rate) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci int i; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci pr_debug("%s(rate=%lu parent_rate=%lu)\n", __func__, rate, parent_rate); 2648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pxa25x_freqs); i++) 2658c2ecf20Sopenharmony_ci if (pxa25x_freqs[i].cpll == rate) 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(pxa25x_freqs)) 2698c2ecf20Sopenharmony_ci return -EINVAL; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci pxa2xx_cpll_change(&pxa25x_freqs[i], mdrefr_dri, MDREFR, CCCR); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ciPARENTS(clk_pxa25x_cpll) = { "osc_3_6864mhz" }; 2768c2ecf20Sopenharmony_ciRATE_OPS(clk_pxa25x_cpll, "cpll"); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void __init pxa25x_register_core(void) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci clkdev_pxa_register(CLK_NONE, "cpll", NULL, 2818c2ecf20Sopenharmony_ci clk_register_clk_pxa25x_cpll()); 2828c2ecf20Sopenharmony_ci clkdev_pxa_register(CLK_NONE, "run", NULL, 2838c2ecf20Sopenharmony_ci clk_register_clk_pxa25x_run()); 2848c2ecf20Sopenharmony_ci clkdev_pxa_register(CLK_CORE, "core", NULL, 2858c2ecf20Sopenharmony_ci clk_register_clk_pxa25x_core()); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void __init pxa25x_register_plls(void) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci clk_register_fixed_rate(NULL, "osc_3_6864mhz", NULL, 2918c2ecf20Sopenharmony_ci CLK_GET_RATE_NOCACHE, 3686400); 2928c2ecf20Sopenharmony_ci clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, 2938c2ecf20Sopenharmony_ci clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, 2948c2ecf20Sopenharmony_ci CLK_GET_RATE_NOCACHE, 2958c2ecf20Sopenharmony_ci 32768)); 2968c2ecf20Sopenharmony_ci clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0); 2978c2ecf20Sopenharmony_ci clk_register_fixed_factor(NULL, "ppll_95_85mhz", "osc_3_6864mhz", 2988c2ecf20Sopenharmony_ci 0, 26, 1); 2998c2ecf20Sopenharmony_ci clk_register_fixed_factor(NULL, "ppll_147_46mhz", "osc_3_6864mhz", 3008c2ecf20Sopenharmony_ci 0, 40, 1); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void __init pxa25x_base_clocks_init(void) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci pxa25x_register_plls(); 3068c2ecf20Sopenharmony_ci pxa25x_register_core(); 3078c2ecf20Sopenharmony_ci clkdev_pxa_register(CLK_NONE, "system_bus", NULL, 3088c2ecf20Sopenharmony_ci clk_register_clk_pxa25x_memory()); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#define DUMMY_CLK(_con_id, _dev_id, _parent) \ 3128c2ecf20Sopenharmony_ci { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent } 3138c2ecf20Sopenharmony_cistruct dummy_clk { 3148c2ecf20Sopenharmony_ci const char *con_id; 3158c2ecf20Sopenharmony_ci const char *dev_id; 3168c2ecf20Sopenharmony_ci const char *parent; 3178c2ecf20Sopenharmony_ci}; 3188c2ecf20Sopenharmony_cistatic struct dummy_clk dummy_clks[] __initdata = { 3198c2ecf20Sopenharmony_ci DUMMY_CLK(NULL, "pxa25x-gpio", "osc_32_768khz"), 3208c2ecf20Sopenharmony_ci DUMMY_CLK(NULL, "pxa26x-gpio", "osc_32_768khz"), 3218c2ecf20Sopenharmony_ci DUMMY_CLK("GPIO11_CLK", NULL, "osc_3_6864mhz"), 3228c2ecf20Sopenharmony_ci DUMMY_CLK("GPIO12_CLK", NULL, "osc_32_768khz"), 3238c2ecf20Sopenharmony_ci DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"), 3248c2ecf20Sopenharmony_ci DUMMY_CLK("OSTIMER0", NULL, "osc_3_6864mhz"), 3258c2ecf20Sopenharmony_ci DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"), 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void __init pxa25x_dummy_clocks_init(void) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct clk *clk; 3318c2ecf20Sopenharmony_ci struct dummy_clk *d; 3328c2ecf20Sopenharmony_ci const char *name; 3338c2ecf20Sopenharmony_ci int i; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * All pinctrl logic has been wiped out of the clock driver, especially 3378c2ecf20Sopenharmony_ci * for gpio11 and gpio12 outputs. Machine code should ensure proper pin 3388c2ecf20Sopenharmony_ci * control (ie. pxa2xx_mfp_config() invocation). 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) { 3418c2ecf20Sopenharmony_ci d = &dummy_clks[i]; 3428c2ecf20Sopenharmony_ci name = d->dev_id ? d->dev_id : d->con_id; 3438c2ecf20Sopenharmony_ci clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1); 3448c2ecf20Sopenharmony_ci clk_register_clkdev(clk, d->con_id, d->dev_id); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint __init pxa25x_clocks_init(void) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci pxa25x_base_clocks_init(); 3518c2ecf20Sopenharmony_ci pxa25x_dummy_clocks_init(); 3528c2ecf20Sopenharmony_ci return clk_pxa_cken_init(pxa25x_clocks, ARRAY_SIZE(pxa25x_clocks)); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void __init pxa25x_dt_clocks_init(struct device_node *np) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci pxa25x_clocks_init(); 3588c2ecf20Sopenharmony_ci clk_pxa_dt_common_init(np); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ciCLK_OF_DECLARE(pxa25x_clks, "marvell,pxa250-core-clocks", 3618c2ecf20Sopenharmony_ci pxa25x_dt_clocks_init); 362