162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Ingenic JZ4725B SoC CGU driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018 Paul Cercueil 662306a36Sopenharmony_ci * Author: Paul Cercueil <paul@crapouillou.net> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/clk-provider.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <dt-bindings/clock/ingenic,jz4725b-cgu.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "cgu.h" 1662306a36Sopenharmony_ci#include "pm.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* CGU register offsets */ 1962306a36Sopenharmony_ci#define CGU_REG_CPCCR 0x00 2062306a36Sopenharmony_ci#define CGU_REG_LCR 0x04 2162306a36Sopenharmony_ci#define CGU_REG_CPPCR 0x10 2262306a36Sopenharmony_ci#define CGU_REG_CLKGR 0x20 2362306a36Sopenharmony_ci#define CGU_REG_OPCR 0x24 2462306a36Sopenharmony_ci#define CGU_REG_I2SCDR 0x60 2562306a36Sopenharmony_ci#define CGU_REG_LPCDR 0x64 2662306a36Sopenharmony_ci#define CGU_REG_MSCCDR 0x68 2762306a36Sopenharmony_ci#define CGU_REG_SSICDR 0x74 2862306a36Sopenharmony_ci#define CGU_REG_CIMCDR 0x78 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* bits within the LCR register */ 3162306a36Sopenharmony_ci#define LCR_SLEEP BIT(0) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic struct ingenic_cgu *cgu; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic const s8 pll_od_encoding[4] = { 3662306a36Sopenharmony_ci 0x0, 0x1, -1, 0x3, 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const u8 jz4725b_cgu_cpccr_div_table[] = { 4062306a36Sopenharmony_ci 1, 2, 3, 4, 6, 8, 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic const u8 jz4725b_cgu_pll_half_div_table[] = { 4462306a36Sopenharmony_ci 2, 1, 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = { 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* External clocks */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT }, 5262306a36Sopenharmony_ci [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci [JZ4725B_CLK_PLL] = { 5562306a36Sopenharmony_ci "pll", CGU_CLK_PLL, 5662306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 5762306a36Sopenharmony_ci .pll = { 5862306a36Sopenharmony_ci .reg = CGU_REG_CPPCR, 5962306a36Sopenharmony_ci .rate_multiplier = 1, 6062306a36Sopenharmony_ci .m_shift = 23, 6162306a36Sopenharmony_ci .m_bits = 9, 6262306a36Sopenharmony_ci .m_offset = 2, 6362306a36Sopenharmony_ci .n_shift = 18, 6462306a36Sopenharmony_ci .n_bits = 5, 6562306a36Sopenharmony_ci .n_offset = 2, 6662306a36Sopenharmony_ci .od_shift = 16, 6762306a36Sopenharmony_ci .od_bits = 2, 6862306a36Sopenharmony_ci .od_max = 4, 6962306a36Sopenharmony_ci .od_encoding = pll_od_encoding, 7062306a36Sopenharmony_ci .stable_bit = 10, 7162306a36Sopenharmony_ci .bypass_reg = CGU_REG_CPPCR, 7262306a36Sopenharmony_ci .bypass_bit = 9, 7362306a36Sopenharmony_ci .enable_bit = 8, 7462306a36Sopenharmony_ci }, 7562306a36Sopenharmony_ci }, 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Muxes & dividers */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci [JZ4725B_CLK_PLL_HALF] = { 8062306a36Sopenharmony_ci "pll half", CGU_CLK_DIV, 8162306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 8262306a36Sopenharmony_ci .div = { 8362306a36Sopenharmony_ci CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0, 8462306a36Sopenharmony_ci jz4725b_cgu_pll_half_div_table, 8562306a36Sopenharmony_ci }, 8662306a36Sopenharmony_ci }, 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci [JZ4725B_CLK_CCLK] = { 8962306a36Sopenharmony_ci "cclk", CGU_CLK_DIV, 9062306a36Sopenharmony_ci /* 9162306a36Sopenharmony_ci * Disabling the CPU clock or any parent clocks will hang the 9262306a36Sopenharmony_ci * system; mark it critical. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci .flags = CLK_IS_CRITICAL, 9562306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 9662306a36Sopenharmony_ci .div = { 9762306a36Sopenharmony_ci CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0, 9862306a36Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 9962306a36Sopenharmony_ci }, 10062306a36Sopenharmony_ci }, 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci [JZ4725B_CLK_HCLK] = { 10362306a36Sopenharmony_ci "hclk", CGU_CLK_DIV, 10462306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 10562306a36Sopenharmony_ci .div = { 10662306a36Sopenharmony_ci CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0, 10762306a36Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 10862306a36Sopenharmony_ci }, 10962306a36Sopenharmony_ci }, 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci [JZ4725B_CLK_PCLK] = { 11262306a36Sopenharmony_ci "pclk", CGU_CLK_DIV, 11362306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 11462306a36Sopenharmony_ci .div = { 11562306a36Sopenharmony_ci CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0, 11662306a36Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 11762306a36Sopenharmony_ci }, 11862306a36Sopenharmony_ci }, 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci [JZ4725B_CLK_MCLK] = { 12162306a36Sopenharmony_ci "mclk", CGU_CLK_DIV, 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * Disabling MCLK or its parents will render DRAM 12462306a36Sopenharmony_ci * inaccessible; mark it critical. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci .flags = CLK_IS_CRITICAL, 12762306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 12862306a36Sopenharmony_ci .div = { 12962306a36Sopenharmony_ci CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0, 13062306a36Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 13162306a36Sopenharmony_ci }, 13262306a36Sopenharmony_ci }, 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci [JZ4725B_CLK_IPU] = { 13562306a36Sopenharmony_ci "ipu", CGU_CLK_DIV | CGU_CLK_GATE, 13662306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 13762306a36Sopenharmony_ci .div = { 13862306a36Sopenharmony_ci CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0, 13962306a36Sopenharmony_ci jz4725b_cgu_cpccr_div_table, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 13 }, 14262306a36Sopenharmony_ci }, 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci [JZ4725B_CLK_LCD] = { 14562306a36Sopenharmony_ci "lcd", CGU_CLK_DIV | CGU_CLK_GATE, 14662306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, 14762306a36Sopenharmony_ci .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 14862306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 9 }, 14962306a36Sopenharmony_ci }, 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci [JZ4725B_CLK_I2S] = { 15262306a36Sopenharmony_ci "i2s", CGU_CLK_MUX | CGU_CLK_DIV, 15362306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, 15462306a36Sopenharmony_ci .mux = { CGU_REG_CPCCR, 31, 1 }, 15562306a36Sopenharmony_ci .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, 15662306a36Sopenharmony_ci }, 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci [JZ4725B_CLK_SPI] = { 15962306a36Sopenharmony_ci "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 16062306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 }, 16162306a36Sopenharmony_ci .mux = { CGU_REG_SSICDR, 31, 1 }, 16262306a36Sopenharmony_ci .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, 16362306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 4 }, 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci [JZ4725B_CLK_MMC_MUX] = { 16762306a36Sopenharmony_ci "mmc_mux", CGU_CLK_DIV, 16862306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, 16962306a36Sopenharmony_ci .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, 17062306a36Sopenharmony_ci }, 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci [JZ4725B_CLK_UDC] = { 17362306a36Sopenharmony_ci "udc", CGU_CLK_MUX | CGU_CLK_DIV, 17462306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, 17562306a36Sopenharmony_ci .mux = { CGU_REG_CPCCR, 29, 1 }, 17662306a36Sopenharmony_ci .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, 17762306a36Sopenharmony_ci }, 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* Gate-only clocks */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci [JZ4725B_CLK_UART] = { 18262306a36Sopenharmony_ci "uart", CGU_CLK_GATE, 18362306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 18462306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 0 }, 18562306a36Sopenharmony_ci }, 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci [JZ4725B_CLK_DMA] = { 18862306a36Sopenharmony_ci "dma", CGU_CLK_GATE, 18962306a36Sopenharmony_ci .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 }, 19062306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 12 }, 19162306a36Sopenharmony_ci }, 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci [JZ4725B_CLK_ADC] = { 19462306a36Sopenharmony_ci "adc", CGU_CLK_GATE, 19562306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 19662306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 7 }, 19762306a36Sopenharmony_ci }, 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci [JZ4725B_CLK_I2C] = { 20062306a36Sopenharmony_ci "i2c", CGU_CLK_GATE, 20162306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 20262306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 3 }, 20362306a36Sopenharmony_ci }, 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci [JZ4725B_CLK_AIC] = { 20662306a36Sopenharmony_ci "aic", CGU_CLK_GATE, 20762306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 20862306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 5 }, 20962306a36Sopenharmony_ci }, 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci [JZ4725B_CLK_MMC0] = { 21262306a36Sopenharmony_ci "mmc0", CGU_CLK_GATE, 21362306a36Sopenharmony_ci .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, 21462306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 6 }, 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci [JZ4725B_CLK_MMC1] = { 21862306a36Sopenharmony_ci "mmc1", CGU_CLK_GATE, 21962306a36Sopenharmony_ci .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, 22062306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 16 }, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci [JZ4725B_CLK_BCH] = { 22462306a36Sopenharmony_ci "bch", CGU_CLK_GATE, 22562306a36Sopenharmony_ci .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 }, 22662306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 11 }, 22762306a36Sopenharmony_ci }, 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci [JZ4725B_CLK_TCU] = { 23062306a36Sopenharmony_ci "tcu", CGU_CLK_GATE, 23162306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 }, 23262306a36Sopenharmony_ci .gate = { CGU_REG_CLKGR, 1 }, 23362306a36Sopenharmony_ci }, 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci [JZ4725B_CLK_EXT512] = { 23662306a36Sopenharmony_ci "ext/512", CGU_CLK_FIXDIV, 23762306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT }, 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Doc calls it EXT512, but it seems to be /256... */ 24062306a36Sopenharmony_ci .fixdiv = { 256 }, 24162306a36Sopenharmony_ci }, 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci [JZ4725B_CLK_RTC] = { 24462306a36Sopenharmony_ci "rtc", CGU_CLK_MUX, 24562306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 }, 24662306a36Sopenharmony_ci .mux = { CGU_REG_OPCR, 2, 1}, 24762306a36Sopenharmony_ci }, 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci [JZ4725B_CLK_UDC_PHY] = { 25062306a36Sopenharmony_ci "udc_phy", CGU_CLK_GATE, 25162306a36Sopenharmony_ci .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 25262306a36Sopenharmony_ci .gate = { CGU_REG_OPCR, 6, true }, 25362306a36Sopenharmony_ci }, 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void __init jz4725b_cgu_init(struct device_node *np) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci int retval; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci cgu = ingenic_cgu_new(jz4725b_cgu_clocks, 26162306a36Sopenharmony_ci ARRAY_SIZE(jz4725b_cgu_clocks), np); 26262306a36Sopenharmony_ci if (!cgu) { 26362306a36Sopenharmony_ci pr_err("%s: failed to initialise CGU\n", __func__); 26462306a36Sopenharmony_ci return; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci retval = ingenic_cgu_register_clocks(cgu); 26862306a36Sopenharmony_ci if (retval) 26962306a36Sopenharmony_ci pr_err("%s: failed to register CGU Clocks\n", __func__); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ingenic_cgu_register_syscore_ops(cgu); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ciCLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init); 274