274 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Ingenic JZ4725B SoC CGU driver4 *5 * Copyright (C) 2018 Paul Cercueil6 * Author: Paul Cercueil <paul@crapouillou.net>7 */8 9#include <linux/clk-provider.h>10#include <linux/delay.h>11#include <linux/of.h>12 13#include <dt-bindings/clock/ingenic,jz4725b-cgu.h>14 15#include "cgu.h"16#include "pm.h"17 18/* CGU register offsets */19#define CGU_REG_CPCCR 0x0020#define CGU_REG_LCR 0x0421#define CGU_REG_CPPCR 0x1022#define CGU_REG_CLKGR 0x2023#define CGU_REG_OPCR 0x2424#define CGU_REG_I2SCDR 0x6025#define CGU_REG_LPCDR 0x6426#define CGU_REG_MSCCDR 0x6827#define CGU_REG_SSICDR 0x7428#define CGU_REG_CIMCDR 0x7829 30/* bits within the LCR register */31#define LCR_SLEEP BIT(0)32 33static struct ingenic_cgu *cgu;34 35static const s8 pll_od_encoding[4] = {36 0x0, 0x1, -1, 0x3,37};38 39static const u8 jz4725b_cgu_cpccr_div_table[] = {40 1, 2, 3, 4, 6, 8,41};42 43static const u8 jz4725b_cgu_pll_half_div_table[] = {44 2, 1,45};46 47static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {48 49 /* External clocks */50 51 [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT },52 [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },53 54 [JZ4725B_CLK_PLL] = {55 "pll", CGU_CLK_PLL,56 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },57 .pll = {58 .reg = CGU_REG_CPPCR,59 .rate_multiplier = 1,60 .m_shift = 23,61 .m_bits = 9,62 .m_offset = 2,63 .n_shift = 18,64 .n_bits = 5,65 .n_offset = 2,66 .od_shift = 16,67 .od_bits = 2,68 .od_max = 4,69 .od_encoding = pll_od_encoding,70 .stable_bit = 10,71 .bypass_reg = CGU_REG_CPPCR,72 .bypass_bit = 9,73 .enable_bit = 8,74 },75 },76 77 /* Muxes & dividers */78 79 [JZ4725B_CLK_PLL_HALF] = {80 "pll half", CGU_CLK_DIV,81 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },82 .div = {83 CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,84 jz4725b_cgu_pll_half_div_table,85 },86 },87 88 [JZ4725B_CLK_CCLK] = {89 "cclk", CGU_CLK_DIV,90 /*91 * Disabling the CPU clock or any parent clocks will hang the92 * system; mark it critical.93 */94 .flags = CLK_IS_CRITICAL,95 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },96 .div = {97 CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,98 jz4725b_cgu_cpccr_div_table,99 },100 },101 102 [JZ4725B_CLK_HCLK] = {103 "hclk", CGU_CLK_DIV,104 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },105 .div = {106 CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,107 jz4725b_cgu_cpccr_div_table,108 },109 },110 111 [JZ4725B_CLK_PCLK] = {112 "pclk", CGU_CLK_DIV,113 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },114 .div = {115 CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,116 jz4725b_cgu_cpccr_div_table,117 },118 },119 120 [JZ4725B_CLK_MCLK] = {121 "mclk", CGU_CLK_DIV,122 /*123 * Disabling MCLK or its parents will render DRAM124 * inaccessible; mark it critical.125 */126 .flags = CLK_IS_CRITICAL,127 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },128 .div = {129 CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,130 jz4725b_cgu_cpccr_div_table,131 },132 },133 134 [JZ4725B_CLK_IPU] = {135 "ipu", CGU_CLK_DIV | CGU_CLK_GATE,136 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },137 .div = {138 CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,139 jz4725b_cgu_cpccr_div_table,140 },141 .gate = { CGU_REG_CLKGR, 13 },142 },143 144 [JZ4725B_CLK_LCD] = {145 "lcd", CGU_CLK_DIV | CGU_CLK_GATE,146 .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },147 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },148 .gate = { CGU_REG_CLKGR, 9 },149 },150 151 [JZ4725B_CLK_I2S] = {152 "i2s", CGU_CLK_MUX | CGU_CLK_DIV,153 .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },154 .mux = { CGU_REG_CPCCR, 31, 1 },155 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },156 },157 158 [JZ4725B_CLK_SPI] = {159 "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,160 .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 },161 .mux = { CGU_REG_SSICDR, 31, 1 },162 .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },163 .gate = { CGU_REG_CLKGR, 4 },164 },165 166 [JZ4725B_CLK_MMC_MUX] = {167 "mmc_mux", CGU_CLK_DIV,168 .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },169 .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },170 },171 172 [JZ4725B_CLK_UDC] = {173 "udc", CGU_CLK_MUX | CGU_CLK_DIV,174 .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },175 .mux = { CGU_REG_CPCCR, 29, 1 },176 .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },177 },178 179 /* Gate-only clocks */180 181 [JZ4725B_CLK_UART] = {182 "uart", CGU_CLK_GATE,183 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },184 .gate = { CGU_REG_CLKGR, 0 },185 },186 187 [JZ4725B_CLK_DMA] = {188 "dma", CGU_CLK_GATE,189 .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 },190 .gate = { CGU_REG_CLKGR, 12 },191 },192 193 [JZ4725B_CLK_ADC] = {194 "adc", CGU_CLK_GATE,195 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },196 .gate = { CGU_REG_CLKGR, 7 },197 },198 199 [JZ4725B_CLK_I2C] = {200 "i2c", CGU_CLK_GATE,201 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },202 .gate = { CGU_REG_CLKGR, 3 },203 },204 205 [JZ4725B_CLK_AIC] = {206 "aic", CGU_CLK_GATE,207 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },208 .gate = { CGU_REG_CLKGR, 5 },209 },210 211 [JZ4725B_CLK_MMC0] = {212 "mmc0", CGU_CLK_GATE,213 .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },214 .gate = { CGU_REG_CLKGR, 6 },215 },216 217 [JZ4725B_CLK_MMC1] = {218 "mmc1", CGU_CLK_GATE,219 .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },220 .gate = { CGU_REG_CLKGR, 16 },221 },222 223 [JZ4725B_CLK_BCH] = {224 "bch", CGU_CLK_GATE,225 .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 },226 .gate = { CGU_REG_CLKGR, 11 },227 },228 229 [JZ4725B_CLK_TCU] = {230 "tcu", CGU_CLK_GATE,231 .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 },232 .gate = { CGU_REG_CLKGR, 1 },233 },234 235 [JZ4725B_CLK_EXT512] = {236 "ext/512", CGU_CLK_FIXDIV,237 .parents = { JZ4725B_CLK_EXT },238 239 /* Doc calls it EXT512, but it seems to be /256... */240 .fixdiv = { 256 },241 },242 243 [JZ4725B_CLK_RTC] = {244 "rtc", CGU_CLK_MUX,245 .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 },246 .mux = { CGU_REG_OPCR, 2, 1},247 },248 249 [JZ4725B_CLK_UDC_PHY] = {250 "udc_phy", CGU_CLK_GATE,251 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },252 .gate = { CGU_REG_OPCR, 6, true },253 },254};255 256static void __init jz4725b_cgu_init(struct device_node *np)257{258 int retval;259 260 cgu = ingenic_cgu_new(jz4725b_cgu_clocks,261 ARRAY_SIZE(jz4725b_cgu_clocks), np);262 if (!cgu) {263 pr_err("%s: failed to initialise CGU\n", __func__);264 return;265 }266 267 retval = ingenic_cgu_register_clocks(cgu);268 if (retval)269 pr_err("%s: failed to register CGU Clocks\n", __func__);270 271 ingenic_cgu_register_syscore_ops(cgu);272}273CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);274