Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Ingenic JZ4725B SoC CGU driver
0004  *
0005  * Copyright (C) 2018 Paul Cercueil
0006  * Author: Paul Cercueil <paul@crapouillou.net>
0007  */
0008 
0009 #include <linux/clk-provider.h>
0010 #include <linux/delay.h>
0011 #include <linux/of.h>
0012 
0013 #include <dt-bindings/clock/ingenic,jz4725b-cgu.h>
0014 
0015 #include "cgu.h"
0016 #include "pm.h"
0017 
0018 /* CGU register offsets */
0019 #define CGU_REG_CPCCR       0x00
0020 #define CGU_REG_LCR     0x04
0021 #define CGU_REG_CPPCR       0x10
0022 #define CGU_REG_CLKGR       0x20
0023 #define CGU_REG_OPCR        0x24
0024 #define CGU_REG_I2SCDR      0x60
0025 #define CGU_REG_LPCDR       0x64
0026 #define CGU_REG_MSCCDR      0x68
0027 #define CGU_REG_SSICDR      0x74
0028 #define CGU_REG_CIMCDR      0x78
0029 
0030 /* bits within the LCR register */
0031 #define LCR_SLEEP       BIT(0)
0032 
0033 static struct ingenic_cgu *cgu;
0034 
0035 static const s8 pll_od_encoding[4] = {
0036     0x0, 0x1, -1, 0x3,
0037 };
0038 
0039 static const u8 jz4725b_cgu_cpccr_div_table[] = {
0040     1, 2, 3, 4, 6, 8,
0041 };
0042 
0043 static const u8 jz4725b_cgu_pll_half_div_table[] = {
0044     2, 1,
0045 };
0046 
0047 static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
0048 
0049     /* External clocks */
0050 
0051     [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT },
0052     [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
0053 
0054     [JZ4725B_CLK_PLL] = {
0055         "pll", CGU_CLK_PLL,
0056         .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
0057         .pll = {
0058             .reg = CGU_REG_CPPCR,
0059             .rate_multiplier = 1,
0060             .m_shift = 23,
0061             .m_bits = 9,
0062             .m_offset = 2,
0063             .n_shift = 18,
0064             .n_bits = 5,
0065             .n_offset = 2,
0066             .od_shift = 16,
0067             .od_bits = 2,
0068             .od_max = 4,
0069             .od_encoding = pll_od_encoding,
0070             .stable_bit = 10,
0071             .bypass_reg = CGU_REG_CPPCR,
0072             .bypass_bit = 9,
0073             .enable_bit = 8,
0074         },
0075     },
0076 
0077     /* Muxes & dividers */
0078 
0079     [JZ4725B_CLK_PLL_HALF] = {
0080         "pll half", CGU_CLK_DIV,
0081         .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
0082         .div = {
0083             CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
0084             jz4725b_cgu_pll_half_div_table,
0085         },
0086     },
0087 
0088     [JZ4725B_CLK_CCLK] = {
0089         "cclk", CGU_CLK_DIV,
0090         /*
0091          * Disabling the CPU clock or any parent clocks will hang the
0092          * system; mark it critical.
0093          */
0094         .flags = CLK_IS_CRITICAL,
0095         .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
0096         .div = {
0097             CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
0098             jz4725b_cgu_cpccr_div_table,
0099         },
0100     },
0101 
0102     [JZ4725B_CLK_HCLK] = {
0103         "hclk", CGU_CLK_DIV,
0104         .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
0105         .div = {
0106             CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
0107             jz4725b_cgu_cpccr_div_table,
0108         },
0109     },
0110 
0111     [JZ4725B_CLK_PCLK] = {
0112         "pclk", CGU_CLK_DIV,
0113         .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
0114         .div = {
0115             CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
0116             jz4725b_cgu_cpccr_div_table,
0117         },
0118     },
0119 
0120     [JZ4725B_CLK_MCLK] = {
0121         "mclk", CGU_CLK_DIV,
0122         /*
0123          * Disabling MCLK or its parents will render DRAM
0124          * inaccessible; mark it critical.
0125          */
0126         .flags = CLK_IS_CRITICAL,
0127         .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
0128         .div = {
0129             CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
0130             jz4725b_cgu_cpccr_div_table,
0131         },
0132     },
0133 
0134     [JZ4725B_CLK_IPU] = {
0135         "ipu", CGU_CLK_DIV | CGU_CLK_GATE,
0136         .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
0137         .div = {
0138             CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
0139             jz4725b_cgu_cpccr_div_table,
0140         },
0141         .gate = { CGU_REG_CLKGR, 13 },
0142     },
0143 
0144     [JZ4725B_CLK_LCD] = {
0145         "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
0146         .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
0147         .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
0148         .gate = { CGU_REG_CLKGR, 9 },
0149     },
0150 
0151     [JZ4725B_CLK_I2S] = {
0152         "i2s", CGU_CLK_MUX | CGU_CLK_DIV,
0153         .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
0154         .mux = { CGU_REG_CPCCR, 31, 1 },
0155         .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
0156     },
0157 
0158     [JZ4725B_CLK_SPI] = {
0159         "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
0160         .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 },
0161         .mux = { CGU_REG_SSICDR, 31, 1 },
0162         .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
0163         .gate = { CGU_REG_CLKGR, 4 },
0164     },
0165 
0166     [JZ4725B_CLK_MMC_MUX] = {
0167         "mmc_mux", CGU_CLK_DIV,
0168         .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
0169         .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
0170     },
0171 
0172     [JZ4725B_CLK_UDC] = {
0173         "udc", CGU_CLK_MUX | CGU_CLK_DIV,
0174         .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
0175         .mux = { CGU_REG_CPCCR, 29, 1 },
0176         .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
0177     },
0178 
0179     /* Gate-only clocks */
0180 
0181     [JZ4725B_CLK_UART] = {
0182         "uart", CGU_CLK_GATE,
0183         .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
0184         .gate = { CGU_REG_CLKGR, 0 },
0185     },
0186 
0187     [JZ4725B_CLK_DMA] = {
0188         "dma", CGU_CLK_GATE,
0189         .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 },
0190         .gate = { CGU_REG_CLKGR, 12 },
0191     },
0192 
0193     [JZ4725B_CLK_ADC] = {
0194         "adc", CGU_CLK_GATE,
0195         .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
0196         .gate = { CGU_REG_CLKGR, 7 },
0197     },
0198 
0199     [JZ4725B_CLK_I2C] = {
0200         "i2c", CGU_CLK_GATE,
0201         .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
0202         .gate = { CGU_REG_CLKGR, 3 },
0203     },
0204 
0205     [JZ4725B_CLK_AIC] = {
0206         "aic", CGU_CLK_GATE,
0207         .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
0208         .gate = { CGU_REG_CLKGR, 5 },
0209     },
0210 
0211     [JZ4725B_CLK_MMC0] = {
0212         "mmc0", CGU_CLK_GATE,
0213         .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
0214         .gate = { CGU_REG_CLKGR, 6 },
0215     },
0216 
0217     [JZ4725B_CLK_MMC1] = {
0218         "mmc1", CGU_CLK_GATE,
0219         .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
0220         .gate = { CGU_REG_CLKGR, 16 },
0221     },
0222 
0223     [JZ4725B_CLK_BCH] = {
0224         "bch", CGU_CLK_GATE,
0225         .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 },
0226         .gate = { CGU_REG_CLKGR, 11 },
0227     },
0228 
0229     [JZ4725B_CLK_TCU] = {
0230         "tcu", CGU_CLK_GATE,
0231         .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 },
0232         .gate = { CGU_REG_CLKGR, 1 },
0233     },
0234 
0235     [JZ4725B_CLK_EXT512] = {
0236         "ext/512", CGU_CLK_FIXDIV,
0237         .parents = { JZ4725B_CLK_EXT },
0238 
0239         /* Doc calls it EXT512, but it seems to be /256... */
0240         .fixdiv = { 256 },
0241     },
0242 
0243     [JZ4725B_CLK_RTC] = {
0244         "rtc", CGU_CLK_MUX,
0245         .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 },
0246         .mux = { CGU_REG_OPCR, 2, 1},
0247     },
0248 
0249     [JZ4725B_CLK_UDC_PHY] = {
0250         "udc_phy", CGU_CLK_GATE,
0251         .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
0252         .gate = { CGU_REG_OPCR, 6, true },
0253     },
0254 };
0255 
0256 static void __init jz4725b_cgu_init(struct device_node *np)
0257 {
0258     int retval;
0259 
0260     cgu = ingenic_cgu_new(jz4725b_cgu_clocks,
0261                   ARRAY_SIZE(jz4725b_cgu_clocks), np);
0262     if (!cgu) {
0263         pr_err("%s: failed to initialise CGU\n", __func__);
0264         return;
0265     }
0266 
0267     retval = ingenic_cgu_register_clocks(cgu);
0268     if (retval)
0269         pr_err("%s: failed to register CGU Clocks\n", __func__);
0270 
0271     ingenic_cgu_register_syscore_ops(cgu);
0272 }
0273 CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);