Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: Add Ingenic jz4725b CGU driver

Add support for the clocks provided by the CGU in the Ingenic JZ4725B
SoC.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Paul Cercueil and committed by
Stephen Boyd
226dfa47 2fdecde7

+236
+10
drivers/clk/ingenic/Kconfig
··· 14 14 15 15 If building for a JZ4740 SoC, you want to say Y here. 16 16 17 + config INGENIC_CGU_JZ4725B 18 + bool "Ingenic JZ4725B CGU driver" 19 + default MACH_JZ4725B 20 + select INGENIC_CGU_COMMON 21 + help 22 + Support the clocks provided by the CGU hardware on Ingenic JZ4725B 23 + and compatible SoCs. 24 + 25 + If building for a JZ4725B SoC, you want to say Y here. 26 + 17 27 config INGENIC_CGU_JZ4770 18 28 bool "Ingenic JZ4770 CGU driver" 19 29 default MACH_JZ4770
+1
drivers/clk/ingenic/Makefile
··· 1 1 obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o 2 2 obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o 3 + obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o 3 4 obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o 4 5 obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o
+225
drivers/clk/ingenic/jz4725b-cgu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Ingenic JZ4725B SoC CGU driver 4 + * 5 + * Copyright (C) 2018 Paul Cercueil 6 + * 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 + #include <dt-bindings/clock/jz4725b-cgu.h> 13 + #include "cgu.h" 14 + 15 + /* CGU register offsets */ 16 + #define CGU_REG_CPCCR 0x00 17 + #define CGU_REG_LCR 0x04 18 + #define CGU_REG_CPPCR 0x10 19 + #define CGU_REG_CLKGR 0x20 20 + #define CGU_REG_OPCR 0x24 21 + #define CGU_REG_I2SCDR 0x60 22 + #define CGU_REG_LPCDR 0x64 23 + #define CGU_REG_MSCCDR 0x68 24 + #define CGU_REG_SSICDR 0x74 25 + #define CGU_REG_CIMCDR 0x78 26 + 27 + /* bits within the LCR register */ 28 + #define LCR_SLEEP BIT(0) 29 + 30 + static struct ingenic_cgu *cgu; 31 + 32 + static const s8 pll_od_encoding[4] = { 33 + 0x0, 0x1, -1, 0x3, 34 + }; 35 + 36 + static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = { 37 + 38 + /* External clocks */ 39 + 40 + [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT }, 41 + [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, 42 + 43 + [JZ4725B_CLK_PLL] = { 44 + "pll", CGU_CLK_PLL, 45 + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 46 + .pll = { 47 + .reg = CGU_REG_CPPCR, 48 + .m_shift = 23, 49 + .m_bits = 9, 50 + .m_offset = 2, 51 + .n_shift = 18, 52 + .n_bits = 5, 53 + .n_offset = 2, 54 + .od_shift = 16, 55 + .od_bits = 2, 56 + .od_max = 4, 57 + .od_encoding = pll_od_encoding, 58 + .stable_bit = 10, 59 + .bypass_bit = 9, 60 + .enable_bit = 8, 61 + }, 62 + }, 63 + 64 + /* Muxes & dividers */ 65 + 66 + [JZ4725B_CLK_PLL_HALF] = { 67 + "pll half", CGU_CLK_DIV, 68 + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 69 + .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 }, 70 + }, 71 + 72 + [JZ4725B_CLK_CCLK] = { 73 + "cclk", CGU_CLK_DIV, 74 + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 75 + .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, 76 + }, 77 + 78 + [JZ4725B_CLK_HCLK] = { 79 + "hclk", CGU_CLK_DIV, 80 + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 81 + .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, 82 + }, 83 + 84 + [JZ4725B_CLK_PCLK] = { 85 + "pclk", CGU_CLK_DIV, 86 + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 87 + .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 }, 88 + }, 89 + 90 + [JZ4725B_CLK_MCLK] = { 91 + "mclk", CGU_CLK_DIV, 92 + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 93 + .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 }, 94 + }, 95 + 96 + [JZ4725B_CLK_IPU] = { 97 + "ipu", CGU_CLK_DIV | CGU_CLK_GATE, 98 + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, 99 + .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 }, 100 + .gate = { CGU_REG_CLKGR, 13 }, 101 + }, 102 + 103 + [JZ4725B_CLK_LCD] = { 104 + "lcd", CGU_CLK_DIV | CGU_CLK_GATE, 105 + .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, 106 + .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 107 + .gate = { CGU_REG_CLKGR, 9 }, 108 + }, 109 + 110 + [JZ4725B_CLK_I2S] = { 111 + "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 112 + .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, 113 + .mux = { CGU_REG_CPCCR, 31, 1 }, 114 + .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, 115 + .gate = { CGU_REG_CLKGR, 6 }, 116 + }, 117 + 118 + [JZ4725B_CLK_SPI] = { 119 + "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 120 + .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 }, 121 + .mux = { CGU_REG_SSICDR, 31, 1 }, 122 + .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, 123 + .gate = { CGU_REG_CLKGR, 4 }, 124 + }, 125 + 126 + [JZ4725B_CLK_MMC_MUX] = { 127 + "mmc_mux", CGU_CLK_DIV, 128 + .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, 129 + .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, 130 + }, 131 + 132 + [JZ4725B_CLK_UDC] = { 133 + "udc", CGU_CLK_MUX | CGU_CLK_DIV, 134 + .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, 135 + .mux = { CGU_REG_CPCCR, 29, 1 }, 136 + .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, 137 + }, 138 + 139 + /* Gate-only clocks */ 140 + 141 + [JZ4725B_CLK_UART] = { 142 + "uart", CGU_CLK_GATE, 143 + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 144 + .gate = { CGU_REG_CLKGR, 0 }, 145 + }, 146 + 147 + [JZ4725B_CLK_DMA] = { 148 + "dma", CGU_CLK_GATE, 149 + .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 }, 150 + .gate = { CGU_REG_CLKGR, 12 }, 151 + }, 152 + 153 + [JZ4725B_CLK_ADC] = { 154 + "adc", CGU_CLK_GATE, 155 + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 156 + .gate = { CGU_REG_CLKGR, 7 }, 157 + }, 158 + 159 + [JZ4725B_CLK_I2C] = { 160 + "i2c", CGU_CLK_GATE, 161 + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 162 + .gate = { CGU_REG_CLKGR, 3 }, 163 + }, 164 + 165 + [JZ4725B_CLK_AIC] = { 166 + "aic", CGU_CLK_GATE, 167 + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, 168 + .gate = { CGU_REG_CLKGR, 5 }, 169 + }, 170 + 171 + [JZ4725B_CLK_MMC0] = { 172 + "mmc0", CGU_CLK_GATE, 173 + .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, 174 + .gate = { CGU_REG_CLKGR, 6 }, 175 + }, 176 + 177 + [JZ4725B_CLK_MMC1] = { 178 + "mmc1", CGU_CLK_GATE, 179 + .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, 180 + .gate = { CGU_REG_CLKGR, 16 }, 181 + }, 182 + 183 + [JZ4725B_CLK_BCH] = { 184 + "bch", CGU_CLK_GATE, 185 + .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 }, 186 + .gate = { CGU_REG_CLKGR, 11 }, 187 + }, 188 + 189 + [JZ4725B_CLK_TCU] = { 190 + "tcu", CGU_CLK_GATE, 191 + .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 }, 192 + .gate = { CGU_REG_CLKGR, 1 }, 193 + }, 194 + 195 + [JZ4725B_CLK_EXT512] = { 196 + "ext/512", CGU_CLK_FIXDIV, 197 + .parents = { JZ4725B_CLK_EXT }, 198 + 199 + /* Doc calls it EXT512, but it seems to be /256... */ 200 + .fixdiv = { 256 }, 201 + }, 202 + 203 + [JZ4725B_CLK_RTC] = { 204 + "rtc", CGU_CLK_MUX, 205 + .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 }, 206 + .mux = { CGU_REG_OPCR, 2, 1}, 207 + }, 208 + }; 209 + 210 + static void __init jz4725b_cgu_init(struct device_node *np) 211 + { 212 + int retval; 213 + 214 + cgu = ingenic_cgu_new(jz4725b_cgu_clocks, 215 + ARRAY_SIZE(jz4725b_cgu_clocks), np); 216 + if (!cgu) { 217 + pr_err("%s: failed to initialise CGU\n", __func__); 218 + return; 219 + } 220 + 221 + retval = ingenic_cgu_register_clocks(cgu); 222 + if (retval) 223 + pr_err("%s: failed to register CGU Clocks\n", __func__); 224 + } 225 + CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);