18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Ingenic JZ4725B SoC CGU driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Paul Cercueil 68c2ecf20Sopenharmony_ci * Author: Paul Cercueil <paul@crapouillou.net> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <dt-bindings/clock/jz4725b-cgu.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "cgu.h" 168c2ecf20Sopenharmony_ci#include "pm.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* CGU register offsets */ 198c2ecf20Sopenharmony_ci#define CGU_REG_CPCCR 0x00 208c2ecf20Sopenharmony_ci#define CGU_REG_LCR 0x04 218c2ecf20Sopenharmony_ci#define CGU_REG_CPPCR 0x10 228c2ecf20Sopenharmony_ci#define CGU_REG_CLKGR 0x20 238c2ecf20Sopenharmony_ci#define CGU_REG_OPCR 0x24 248c2ecf20Sopenharmony_ci#define CGU_REG_I2SCDR 0x60 258c2ecf20Sopenharmony_ci#define CGU_REG_LPCDR 0x64 268c2ecf20Sopenharmony_ci#define CGU_REG_MSCCDR 0x68 278c2ecf20Sopenharmony_ci#define CGU_REG_SSICDR 0x74 288c2ecf20Sopenharmony_ci#define CGU_REG_CIMCDR 0x78 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* bits within the LCR register */ 318c2ecf20Sopenharmony_ci#define LCR_SLEEP BIT(0) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct ingenic_cgu *cgu; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const s8 pll_od_encoding[4] = { 368c2ecf20Sopenharmony_ci 0x0, 0x1, -1, 0x3, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const u8 jz4725b_cgu_cpccr_div_table[] = { 408c2ecf20Sopenharmony_ci 1, 2, 3, 4, 6, 8, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic const u8 jz4725b_cgu_pll_half_div_table[] = { 448c2ecf20Sopenharmony_ci 2, 1, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = { 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* External clocks */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT }, 528c2ecf20Sopenharmony_ci [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci [JZ4725B_CLK_PLL] = { 558c2ecf20Sopenharmony_ci "pll", CGU_CLK_PLL, 568c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 578c2ecf20Sopenharmony_ci .pll = { 588c2ecf20Sopenharmony_ci .reg = CGU_REG_CPPCR, 598c2ecf20Sopenharmony_ci .rate_multiplier = 1, 608c2ecf20Sopenharmony_ci .m_shift = 23, 618c2ecf20Sopenharmony_ci .m_bits = 9, 628c2ecf20Sopenharmony_ci .m_offset = 2, 638c2ecf20Sopenharmony_ci .n_shift = 18, 648c2ecf20Sopenharmony_ci .n_bits = 5, 658c2ecf20Sopenharmony_ci .n_offset = 2, 668c2ecf20Sopenharmony_ci .od_shift = 16, 678c2ecf20Sopenharmony_ci .od_bits = 2, 688c2ecf20Sopenharmony_ci .od_max = 4, 698c2ecf20Sopenharmony_ci .od_encoding = pll_od_encoding, 708c2ecf20Sopenharmony_ci .stable_bit = 10, 718c2ecf20Sopenharmony_ci .bypass_reg = CGU_REG_CPPCR, 728c2ecf20Sopenharmony_ci .bypass_bit = 9, 738c2ecf20Sopenharmony_ci .enable_bit = 8, 748c2ecf20Sopenharmony_ci }, 758c2ecf20Sopenharmony_ci }, 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Muxes & dividers */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci [JZ4725B_CLK_PLL_HALF] = { 808c2ecf20Sopenharmony_ci "pll half", CGU_CLK_DIV, 818c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 828c2ecf20Sopenharmony_ci .div = { 838c2ecf20Sopenharmony_ci CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 848c2ecf20Sopenharmony_ci jz4725b_cgu_pll_half_div_table, 858c2ecf20Sopenharmony_ci }, 868c2ecf20Sopenharmony_ci }, 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci [JZ4725B_CLK_CCLK] = { 898c2ecf20Sopenharmony_ci "cclk", CGU_CLK_DIV, 908c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 918c2ecf20Sopenharmony_ci .div = { 928c2ecf20Sopenharmony_ci CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 938c2ecf20Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 948c2ecf20Sopenharmony_ci }, 958c2ecf20Sopenharmony_ci }, 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci [JZ4725B_CLK_HCLK] = { 988c2ecf20Sopenharmony_ci "hclk", CGU_CLK_DIV, 998c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 1008c2ecf20Sopenharmony_ci .div = { 1018c2ecf20Sopenharmony_ci CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 1028c2ecf20Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 1038c2ecf20Sopenharmony_ci }, 1048c2ecf20Sopenharmony_ci }, 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci [JZ4725B_CLK_PCLK] = { 1078c2ecf20Sopenharmony_ci "pclk", CGU_CLK_DIV, 1088c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 1098c2ecf20Sopenharmony_ci .div = { 1108c2ecf20Sopenharmony_ci CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 1118c2ecf20Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 1128c2ecf20Sopenharmony_ci }, 1138c2ecf20Sopenharmony_ci }, 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci [JZ4725B_CLK_MCLK] = { 1168c2ecf20Sopenharmony_ci "mclk", CGU_CLK_DIV, 1178c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 1188c2ecf20Sopenharmony_ci .div = { 1198c2ecf20Sopenharmony_ci CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 1208c2ecf20Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci }, 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci [JZ4725B_CLK_IPU] = { 1258c2ecf20Sopenharmony_ci "ipu", CGU_CLK_DIV | CGU_CLK_GATE, 1268c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 1278c2ecf20Sopenharmony_ci .div = { 1288c2ecf20Sopenharmony_ci CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 1298c2ecf20Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 13 }, 1328c2ecf20Sopenharmony_ci }, 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci [JZ4725B_CLK_LCD] = { 1358c2ecf20Sopenharmony_ci "lcd", CGU_CLK_DIV | CGU_CLK_GATE, 1368c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, 1378c2ecf20Sopenharmony_ci .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 1388c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 9 }, 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci [JZ4725B_CLK_I2S] = { 1428c2ecf20Sopenharmony_ci "i2s", CGU_CLK_MUX | CGU_CLK_DIV, 1438c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, 1448c2ecf20Sopenharmony_ci .mux = { CGU_REG_CPCCR, 31, 1 }, 1458c2ecf20Sopenharmony_ci .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci [JZ4725B_CLK_SPI] = { 1498c2ecf20Sopenharmony_ci "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 1508c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 }, 1518c2ecf20Sopenharmony_ci .mux = { CGU_REG_SSICDR, 31, 1 }, 1528c2ecf20Sopenharmony_ci .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, 1538c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 4 }, 1548c2ecf20Sopenharmony_ci }, 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci [JZ4725B_CLK_MMC_MUX] = { 1578c2ecf20Sopenharmony_ci "mmc_mux", CGU_CLK_DIV, 1588c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, 1598c2ecf20Sopenharmony_ci .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, 1608c2ecf20Sopenharmony_ci }, 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci [JZ4725B_CLK_UDC] = { 1638c2ecf20Sopenharmony_ci "udc", CGU_CLK_MUX | CGU_CLK_DIV, 1648c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, 1658c2ecf20Sopenharmony_ci .mux = { CGU_REG_CPCCR, 29, 1 }, 1668c2ecf20Sopenharmony_ci .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Gate-only clocks */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci [JZ4725B_CLK_UART] = { 1728c2ecf20Sopenharmony_ci "uart", CGU_CLK_GATE, 1738c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 1748c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 0 }, 1758c2ecf20Sopenharmony_ci }, 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci [JZ4725B_CLK_DMA] = { 1788c2ecf20Sopenharmony_ci "dma", CGU_CLK_GATE, 1798c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 }, 1808c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 12 }, 1818c2ecf20Sopenharmony_ci }, 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci [JZ4725B_CLK_ADC] = { 1848c2ecf20Sopenharmony_ci "adc", CGU_CLK_GATE, 1858c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 1868c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 7 }, 1878c2ecf20Sopenharmony_ci }, 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci [JZ4725B_CLK_I2C] = { 1908c2ecf20Sopenharmony_ci "i2c", CGU_CLK_GATE, 1918c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 1928c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 3 }, 1938c2ecf20Sopenharmony_ci }, 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci [JZ4725B_CLK_AIC] = { 1968c2ecf20Sopenharmony_ci "aic", CGU_CLK_GATE, 1978c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 1988c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 5 }, 1998c2ecf20Sopenharmony_ci }, 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci [JZ4725B_CLK_MMC0] = { 2028c2ecf20Sopenharmony_ci "mmc0", CGU_CLK_GATE, 2038c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, 2048c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 6 }, 2058c2ecf20Sopenharmony_ci }, 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci [JZ4725B_CLK_MMC1] = { 2088c2ecf20Sopenharmony_ci "mmc1", CGU_CLK_GATE, 2098c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, 2108c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 16 }, 2118c2ecf20Sopenharmony_ci }, 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci [JZ4725B_CLK_BCH] = { 2148c2ecf20Sopenharmony_ci "bch", CGU_CLK_GATE, 2158c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 }, 2168c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 11 }, 2178c2ecf20Sopenharmony_ci }, 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci [JZ4725B_CLK_TCU] = { 2208c2ecf20Sopenharmony_ci "tcu", CGU_CLK_GATE, 2218c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 }, 2228c2ecf20Sopenharmony_ci .gate = { CGU_REG_CLKGR, 1 }, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci [JZ4725B_CLK_EXT512] = { 2268c2ecf20Sopenharmony_ci "ext/512", CGU_CLK_FIXDIV, 2278c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT }, 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Doc calls it EXT512, but it seems to be /256... */ 2308c2ecf20Sopenharmony_ci .fixdiv = { 256 }, 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci [JZ4725B_CLK_RTC] = { 2348c2ecf20Sopenharmony_ci "rtc", CGU_CLK_MUX, 2358c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 }, 2368c2ecf20Sopenharmony_ci .mux = { CGU_REG_OPCR, 2, 1}, 2378c2ecf20Sopenharmony_ci }, 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci [JZ4725B_CLK_UDC_PHY] = { 2408c2ecf20Sopenharmony_ci "udc_phy", CGU_CLK_GATE, 2418c2ecf20Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 2428c2ecf20Sopenharmony_ci .gate = { CGU_REG_OPCR, 6, true }, 2438c2ecf20Sopenharmony_ci }, 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void __init jz4725b_cgu_init(struct device_node *np) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int retval; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci cgu = ingenic_cgu_new(jz4725b_cgu_clocks, 2518c2ecf20Sopenharmony_ci ARRAY_SIZE(jz4725b_cgu_clocks), np); 2528c2ecf20Sopenharmony_ci if (!cgu) { 2538c2ecf20Sopenharmony_ci pr_err("%s: failed to initialise CGU\n", __func__); 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci retval = ingenic_cgu_register_clocks(cgu); 2588c2ecf20Sopenharmony_ci if (retval) 2598c2ecf20Sopenharmony_ci pr_err("%s: failed to register CGU Clocks\n", __func__); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci ingenic_cgu_register_syscore_ops(cgu); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciCLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init); 264