1*ff1930c6SPaul Burton /* 2*ff1930c6SPaul Burton * Ingenic JZ4740 SoC CGU driver 3*ff1930c6SPaul Burton * 4*ff1930c6SPaul Burton * Copyright (c) 2015 Imagination Technologies 5*ff1930c6SPaul Burton * Author: Paul Burton <paul.burton@imgtec.com> 6*ff1930c6SPaul Burton * 7*ff1930c6SPaul Burton * This program is free software; you can redistribute it and/or 8*ff1930c6SPaul Burton * modify it under the terms of the GNU General Public License as 9*ff1930c6SPaul Burton * published by the Free Software Foundation; either version 2 of 10*ff1930c6SPaul Burton * the License, or (at your option) any later version. 11*ff1930c6SPaul Burton * 12*ff1930c6SPaul Burton * This program is distributed in the hope that it will be useful, 13*ff1930c6SPaul Burton * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*ff1930c6SPaul Burton * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*ff1930c6SPaul Burton * GNU General Public License for more details. 16*ff1930c6SPaul Burton */ 17*ff1930c6SPaul Burton 18*ff1930c6SPaul Burton #include <linux/clk-provider.h> 19*ff1930c6SPaul Burton #include <linux/delay.h> 20*ff1930c6SPaul Burton #include <linux/of.h> 21*ff1930c6SPaul Burton #include <dt-bindings/clock/jz4740-cgu.h> 22*ff1930c6SPaul Burton #include "cgu.h" 23*ff1930c6SPaul Burton 24*ff1930c6SPaul Burton /* CGU register offsets */ 25*ff1930c6SPaul Burton #define CGU_REG_CPCCR 0x00 26*ff1930c6SPaul Burton #define CGU_REG_CPPCR 0x10 27*ff1930c6SPaul Burton #define CGU_REG_SCR 0x24 28*ff1930c6SPaul Burton #define CGU_REG_I2SCDR 0x60 29*ff1930c6SPaul Burton #define CGU_REG_LPCDR 0x64 30*ff1930c6SPaul Burton #define CGU_REG_MSCCDR 0x68 31*ff1930c6SPaul Burton #define CGU_REG_UHCCDR 0x6c 32*ff1930c6SPaul Burton #define CGU_REG_SSICDR 0x74 33*ff1930c6SPaul Burton 34*ff1930c6SPaul Burton /* bits within a PLL control register */ 35*ff1930c6SPaul Burton #define PLLCTL_M_SHIFT 23 36*ff1930c6SPaul Burton #define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT) 37*ff1930c6SPaul Burton #define PLLCTL_N_SHIFT 18 38*ff1930c6SPaul Burton #define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT) 39*ff1930c6SPaul Burton #define PLLCTL_OD_SHIFT 16 40*ff1930c6SPaul Burton #define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT) 41*ff1930c6SPaul Burton #define PLLCTL_STABLE (1 << 10) 42*ff1930c6SPaul Burton #define PLLCTL_BYPASS (1 << 9) 43*ff1930c6SPaul Burton #define PLLCTL_ENABLE (1 << 8) 44*ff1930c6SPaul Burton 45*ff1930c6SPaul Burton static struct ingenic_cgu *cgu; 46*ff1930c6SPaul Burton 47*ff1930c6SPaul Burton static const s8 pll_od_encoding[4] = { 48*ff1930c6SPaul Burton 0x0, 0x1, -1, 0x3, 49*ff1930c6SPaul Burton }; 50*ff1930c6SPaul Burton 51*ff1930c6SPaul Burton static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { 52*ff1930c6SPaul Burton 53*ff1930c6SPaul Burton /* External clocks */ 54*ff1930c6SPaul Burton 55*ff1930c6SPaul Burton [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT }, 56*ff1930c6SPaul Burton [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT }, 57*ff1930c6SPaul Burton 58*ff1930c6SPaul Burton [JZ4740_CLK_PLL] = { 59*ff1930c6SPaul Burton "pll", CGU_CLK_PLL, 60*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 61*ff1930c6SPaul Burton .pll = { 62*ff1930c6SPaul Burton .reg = CGU_REG_CPPCR, 63*ff1930c6SPaul Burton .m_shift = 23, 64*ff1930c6SPaul Burton .m_bits = 9, 65*ff1930c6SPaul Burton .m_offset = 2, 66*ff1930c6SPaul Burton .n_shift = 18, 67*ff1930c6SPaul Burton .n_bits = 5, 68*ff1930c6SPaul Burton .n_offset = 2, 69*ff1930c6SPaul Burton .od_shift = 16, 70*ff1930c6SPaul Burton .od_bits = 2, 71*ff1930c6SPaul Burton .od_max = 4, 72*ff1930c6SPaul Burton .od_encoding = pll_od_encoding, 73*ff1930c6SPaul Burton .stable_bit = 10, 74*ff1930c6SPaul Burton .bypass_bit = 9, 75*ff1930c6SPaul Burton .enable_bit = 8, 76*ff1930c6SPaul Burton }, 77*ff1930c6SPaul Burton }, 78*ff1930c6SPaul Burton 79*ff1930c6SPaul Burton /* Muxes & dividers */ 80*ff1930c6SPaul Burton 81*ff1930c6SPaul Burton [JZ4740_CLK_PLL_HALF] = { 82*ff1930c6SPaul Burton "pll half", CGU_CLK_DIV, 83*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 84*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 }, 85*ff1930c6SPaul Burton }, 86*ff1930c6SPaul Burton 87*ff1930c6SPaul Burton [JZ4740_CLK_CCLK] = { 88*ff1930c6SPaul Burton "cclk", CGU_CLK_DIV, 89*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 90*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 }, 91*ff1930c6SPaul Burton }, 92*ff1930c6SPaul Burton 93*ff1930c6SPaul Burton [JZ4740_CLK_HCLK] = { 94*ff1930c6SPaul Burton "hclk", CGU_CLK_DIV, 95*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 96*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 }, 97*ff1930c6SPaul Burton }, 98*ff1930c6SPaul Burton 99*ff1930c6SPaul Burton [JZ4740_CLK_PCLK] = { 100*ff1930c6SPaul Burton "pclk", CGU_CLK_DIV, 101*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 102*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 }, 103*ff1930c6SPaul Burton }, 104*ff1930c6SPaul Burton 105*ff1930c6SPaul Burton [JZ4740_CLK_MCLK] = { 106*ff1930c6SPaul Burton "mclk", CGU_CLK_DIV, 107*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 108*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 }, 109*ff1930c6SPaul Burton }, 110*ff1930c6SPaul Burton 111*ff1930c6SPaul Burton [JZ4740_CLK_LCD] = { 112*ff1930c6SPaul Burton "lcd", CGU_CLK_DIV | CGU_CLK_GATE, 113*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 114*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 }, 115*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 10 }, 116*ff1930c6SPaul Burton }, 117*ff1930c6SPaul Burton 118*ff1930c6SPaul Burton [JZ4740_CLK_LCD_PCLK] = { 119*ff1930c6SPaul Burton "lcd_pclk", CGU_CLK_DIV, 120*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 121*ff1930c6SPaul Burton .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 }, 122*ff1930c6SPaul Burton }, 123*ff1930c6SPaul Burton 124*ff1930c6SPaul Burton [JZ4740_CLK_I2S] = { 125*ff1930c6SPaul Burton "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 126*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, 127*ff1930c6SPaul Burton .mux = { CGU_REG_CPCCR, 31, 1 }, 128*ff1930c6SPaul Burton .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 }, 129*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 6 }, 130*ff1930c6SPaul Burton }, 131*ff1930c6SPaul Burton 132*ff1930c6SPaul Burton [JZ4740_CLK_SPI] = { 133*ff1930c6SPaul Burton "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 134*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 }, 135*ff1930c6SPaul Burton .mux = { CGU_REG_SSICDR, 31, 1 }, 136*ff1930c6SPaul Burton .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 }, 137*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 4 }, 138*ff1930c6SPaul Burton }, 139*ff1930c6SPaul Burton 140*ff1930c6SPaul Burton [JZ4740_CLK_MMC] = { 141*ff1930c6SPaul Burton "mmc", CGU_CLK_DIV | CGU_CLK_GATE, 142*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 143*ff1930c6SPaul Burton .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 }, 144*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 7 }, 145*ff1930c6SPaul Burton }, 146*ff1930c6SPaul Burton 147*ff1930c6SPaul Burton [JZ4740_CLK_UHC] = { 148*ff1930c6SPaul Burton "uhc", CGU_CLK_DIV | CGU_CLK_GATE, 149*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 150*ff1930c6SPaul Burton .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 }, 151*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 14 }, 152*ff1930c6SPaul Burton }, 153*ff1930c6SPaul Burton 154*ff1930c6SPaul Burton [JZ4740_CLK_UDC] = { 155*ff1930c6SPaul Burton "udc", CGU_CLK_MUX | CGU_CLK_DIV, 156*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, 157*ff1930c6SPaul Burton .mux = { CGU_REG_CPCCR, 29, 1 }, 158*ff1930c6SPaul Burton .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 }, 159*ff1930c6SPaul Burton .gate = { CGU_REG_SCR, 6 }, 160*ff1930c6SPaul Burton }, 161*ff1930c6SPaul Burton 162*ff1930c6SPaul Burton /* Gate-only clocks */ 163*ff1930c6SPaul Burton 164*ff1930c6SPaul Burton [JZ4740_CLK_UART0] = { 165*ff1930c6SPaul Burton "uart0", CGU_CLK_GATE, 166*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 167*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 0 }, 168*ff1930c6SPaul Burton }, 169*ff1930c6SPaul Burton 170*ff1930c6SPaul Burton [JZ4740_CLK_UART1] = { 171*ff1930c6SPaul Burton "uart1", CGU_CLK_GATE, 172*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 173*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 15 }, 174*ff1930c6SPaul Burton }, 175*ff1930c6SPaul Burton 176*ff1930c6SPaul Burton [JZ4740_CLK_DMA] = { 177*ff1930c6SPaul Burton "dma", CGU_CLK_GATE, 178*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PCLK, -1, -1, -1 }, 179*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 12 }, 180*ff1930c6SPaul Burton }, 181*ff1930c6SPaul Burton 182*ff1930c6SPaul Burton [JZ4740_CLK_IPU] = { 183*ff1930c6SPaul Burton "ipu", CGU_CLK_GATE, 184*ff1930c6SPaul Burton .parents = { JZ4740_CLK_PCLK, -1, -1, -1 }, 185*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 13 }, 186*ff1930c6SPaul Burton }, 187*ff1930c6SPaul Burton 188*ff1930c6SPaul Burton [JZ4740_CLK_ADC] = { 189*ff1930c6SPaul Burton "adc", CGU_CLK_GATE, 190*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 191*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 8 }, 192*ff1930c6SPaul Burton }, 193*ff1930c6SPaul Burton 194*ff1930c6SPaul Burton [JZ4740_CLK_I2C] = { 195*ff1930c6SPaul Burton "i2c", CGU_CLK_GATE, 196*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 197*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 3 }, 198*ff1930c6SPaul Burton }, 199*ff1930c6SPaul Burton 200*ff1930c6SPaul Burton [JZ4740_CLK_AIC] = { 201*ff1930c6SPaul Burton "aic", CGU_CLK_GATE, 202*ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 203*ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 5 }, 204*ff1930c6SPaul Burton }, 205*ff1930c6SPaul Burton }; 206*ff1930c6SPaul Burton 207*ff1930c6SPaul Burton static void __init jz4740_cgu_init(struct device_node *np) 208*ff1930c6SPaul Burton { 209*ff1930c6SPaul Burton int retval; 210*ff1930c6SPaul Burton 211*ff1930c6SPaul Burton cgu = ingenic_cgu_new(jz4740_cgu_clocks, 212*ff1930c6SPaul Burton ARRAY_SIZE(jz4740_cgu_clocks), np); 213*ff1930c6SPaul Burton if (!cgu) { 214*ff1930c6SPaul Burton pr_err("%s: failed to initialise CGU\n", __func__); 215*ff1930c6SPaul Burton return; 216*ff1930c6SPaul Burton } 217*ff1930c6SPaul Burton 218*ff1930c6SPaul Burton retval = ingenic_cgu_register_clocks(cgu); 219*ff1930c6SPaul Burton if (retval) 220*ff1930c6SPaul Burton pr_err("%s: failed to register CGU Clocks\n", __func__); 221*ff1930c6SPaul Burton } 222*ff1930c6SPaul Burton CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init); 223