1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2024 Arm Ltd. 4 * Based on the D1 CCU driver: 5 * Copyright (c) 2020 huangzhenwei@allwinnertech.com 6 * Copyright (C) 2021 Samuel Holland <samuel@sholland.org> 7 */ 8 9 #include <linux/clk-provider.h> 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 13 #include "ccu_common.h" 14 #include "ccu_reset.h" 15 16 #include "ccu_gate.h" 17 #include "ccu_mp.h" 18 19 #include "ccu-sun55i-a523-r.h" 20 21 static const struct clk_parent_data r_ahb_apb_parents[] = { 22 { .fw_name = "hosc" }, 23 { .fw_name = "losc" }, 24 { .fw_name = "iosc" }, 25 { .fw_name = "pll-periph" }, 26 { .fw_name = "pll-audio" }, 27 }; 28 static SUNXI_CCU_M_DATA_WITH_MUX(r_ahb_clk, "r-ahb", 29 r_ahb_apb_parents, 0x000, 30 0, 5, /* M */ 31 24, 3, /* mux */ 32 0); 33 34 static SUNXI_CCU_M_DATA_WITH_MUX(r_apb0_clk, "r-apb0", 35 r_ahb_apb_parents, 0x00c, 36 0, 5, /* M */ 37 24, 3, /* mux */ 38 0); 39 40 static SUNXI_CCU_M_DATA_WITH_MUX(r_apb1_clk, "r-apb1", 41 r_ahb_apb_parents, 0x010, 42 0, 5, /* M */ 43 24, 3, /* mux */ 44 0); 45 46 static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(r_cpu_timer0, "r-timer0", 47 r_ahb_apb_parents, 0x100, 48 0, 0, /* no M */ 49 1, 3, /* P */ 50 4, 3, /* mux */ 51 BIT(0), 52 0); 53 static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(r_cpu_timer1, "r-timer1", 54 r_ahb_apb_parents, 0x104, 55 0, 0, /* no M */ 56 1, 3, /* P */ 57 4, 3, /* mux */ 58 BIT(0), 59 0); 60 static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(r_cpu_timer2, "r-timer2", 61 r_ahb_apb_parents, 0x108, 62 0, 0, /* no M */ 63 1, 3, /* P */ 64 4, 3, /* mux */ 65 BIT(0), 66 0); 67 68 static SUNXI_CCU_GATE_HW(bus_r_timer_clk, "bus-r-timer", &r_ahb_clk.common.hw, 69 0x11c, BIT(0), 0); 70 static SUNXI_CCU_GATE_HW(bus_r_twd_clk, "bus-r-twd", &r_apb0_clk.common.hw, 71 0x12c, BIT(0), 0); 72 73 static const struct clk_parent_data r_pwmctrl_parents[] = { 74 { .fw_name = "hosc" }, 75 { .fw_name = "losc" }, 76 { .fw_name = "iosc" }, 77 }; 78 static SUNXI_CCU_MUX_DATA_WITH_GATE(r_pwmctrl_clk, "r-pwmctrl", 79 r_pwmctrl_parents, 0x130, 80 24, 2, /* mux */ 81 BIT(31), 82 0); 83 static SUNXI_CCU_GATE_HW(bus_r_pwmctrl_clk, "bus-r-pwmctrl", 84 &r_apb0_clk.common.hw, 0x13c, BIT(0), 0); 85 86 /* SPI clock is /M/N (same as new MMC?) */ 87 static SUNXI_CCU_GATE_HW(bus_r_spi_clk, "bus-r-spi", 88 &r_ahb_clk.common.hw, 0x15c, BIT(0), 0); 89 static SUNXI_CCU_GATE_HW(bus_r_spinlock_clk, "bus-r-spinlock", 90 &r_ahb_clk.common.hw, 0x16c, BIT(0), 0); 91 static SUNXI_CCU_GATE_HW(bus_r_msgbox_clk, "bus-r-msgbox", 92 &r_ahb_clk.common.hw, 0x17c, BIT(0), 0); 93 static SUNXI_CCU_GATE_HW(bus_r_uart0_clk, "bus-r-uart0", 94 &r_apb1_clk.common.hw, 0x18c, BIT(0), 0); 95 static SUNXI_CCU_GATE_HW(bus_r_uart1_clk, "bus-r-uart1", 96 &r_apb1_clk.common.hw, 0x18c, BIT(1), 0); 97 static SUNXI_CCU_GATE_HW(bus_r_i2c0_clk, "bus-r-i2c0", 98 &r_apb1_clk.common.hw, 0x19c, BIT(0), 0); 99 static SUNXI_CCU_GATE_HW(bus_r_i2c1_clk, "bus-r-i2c1", 100 &r_apb1_clk.common.hw, 0x19c, BIT(1), 0); 101 static SUNXI_CCU_GATE_HW(bus_r_i2c2_clk, "bus-r-i2c2", 102 &r_apb1_clk.common.hw, 0x19c, BIT(2), 0); 103 static SUNXI_CCU_GATE_HW(bus_r_ppu0_clk, "bus-r-ppu0", 104 &r_apb0_clk.common.hw, 0x1ac, BIT(0), 0); 105 static SUNXI_CCU_GATE_HW(bus_r_ppu1_clk, "bus-r-ppu1", 106 &r_apb0_clk.common.hw, 0x1ac, BIT(1), 0); 107 static SUNXI_CCU_GATE_HW(bus_r_cpu_bist_clk, "bus-r-cpu-bist", 108 &r_apb0_clk.common.hw, 0x1bc, BIT(0), 0); 109 110 static const struct clk_parent_data r_ir_rx_parents[] = { 111 { .fw_name = "losc" }, 112 { .fw_name = "hosc" }, 113 }; 114 static SUNXI_CCU_M_DATA_WITH_MUX_GATE(r_ir_rx_clk, "r-ir-rx", 115 r_ir_rx_parents, 0x1c0, 116 0, 5, /* M */ 117 24, 2, /* mux */ 118 BIT(31), /* gate */ 119 0); 120 static SUNXI_CCU_GATE_HW(bus_r_ir_rx_clk, "bus-r-ir-rx", 121 &r_apb0_clk.common.hw, 0x1cc, BIT(0), 0); 122 123 static SUNXI_CCU_GATE_HW(bus_r_dma_clk, "bus-r-dma", 124 &r_apb0_clk.common.hw, 0x1dc, BIT(0), 0); 125 static SUNXI_CCU_GATE_HW(bus_r_rtc_clk, "bus-r-rtc", 126 &r_apb0_clk.common.hw, 0x20c, BIT(0), 0); 127 static SUNXI_CCU_GATE_HW(bus_r_cpucfg_clk, "bus-r-cpucfg", 128 &r_apb0_clk.common.hw, 0x22c, BIT(0), 0); 129 130 static struct ccu_common *sun55i_a523_r_ccu_clks[] = { 131 &r_ahb_clk.common, 132 &r_apb0_clk.common, 133 &r_apb1_clk.common, 134 &r_cpu_timer0.common, 135 &r_cpu_timer1.common, 136 &r_cpu_timer2.common, 137 &bus_r_timer_clk.common, 138 &bus_r_twd_clk.common, 139 &r_pwmctrl_clk.common, 140 &bus_r_pwmctrl_clk.common, 141 &bus_r_spi_clk.common, 142 &bus_r_spinlock_clk.common, 143 &bus_r_msgbox_clk.common, 144 &bus_r_uart0_clk.common, 145 &bus_r_uart1_clk.common, 146 &bus_r_i2c0_clk.common, 147 &bus_r_i2c1_clk.common, 148 &bus_r_i2c2_clk.common, 149 &bus_r_ppu0_clk.common, 150 &bus_r_ppu1_clk.common, 151 &bus_r_cpu_bist_clk.common, 152 &r_ir_rx_clk.common, 153 &bus_r_ir_rx_clk.common, 154 &bus_r_dma_clk.common, 155 &bus_r_rtc_clk.common, 156 &bus_r_cpucfg_clk.common, 157 }; 158 159 static struct clk_hw_onecell_data sun55i_a523_r_hw_clks = { 160 .num = CLK_NUMBER, 161 .hws = { 162 [CLK_R_AHB] = &r_ahb_clk.common.hw, 163 [CLK_R_APB0] = &r_apb0_clk.common.hw, 164 [CLK_R_APB1] = &r_apb1_clk.common.hw, 165 [CLK_R_TIMER0] = &r_cpu_timer0.common.hw, 166 [CLK_R_TIMER1] = &r_cpu_timer1.common.hw, 167 [CLK_R_TIMER2] = &r_cpu_timer2.common.hw, 168 [CLK_BUS_R_TIMER] = &bus_r_timer_clk.common.hw, 169 [CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw, 170 [CLK_R_PWMCTRL] = &r_pwmctrl_clk.common.hw, 171 [CLK_BUS_R_PWMCTRL] = &bus_r_pwmctrl_clk.common.hw, 172 [CLK_BUS_R_SPI] = &bus_r_spi_clk.common.hw, 173 [CLK_BUS_R_SPINLOCK] = &bus_r_spinlock_clk.common.hw, 174 [CLK_BUS_R_MSGBOX] = &bus_r_msgbox_clk.common.hw, 175 [CLK_BUS_R_UART0] = &bus_r_uart0_clk.common.hw, 176 [CLK_BUS_R_UART1] = &bus_r_uart1_clk.common.hw, 177 [CLK_BUS_R_I2C0] = &bus_r_i2c0_clk.common.hw, 178 [CLK_BUS_R_I2C1] = &bus_r_i2c1_clk.common.hw, 179 [CLK_BUS_R_I2C2] = &bus_r_i2c2_clk.common.hw, 180 [CLK_BUS_R_PPU0] = &bus_r_ppu0_clk.common.hw, 181 [CLK_BUS_R_PPU1] = &bus_r_ppu1_clk.common.hw, 182 [CLK_BUS_R_CPU_BIST] = &bus_r_cpu_bist_clk.common.hw, 183 [CLK_R_IR_RX] = &r_ir_rx_clk.common.hw, 184 [CLK_BUS_R_IR_RX] = &bus_r_ir_rx_clk.common.hw, 185 [CLK_BUS_R_DMA] = &bus_r_dma_clk.common.hw, 186 [CLK_BUS_R_RTC] = &bus_r_rtc_clk.common.hw, 187 [CLK_BUS_R_CPUCFG] = &bus_r_cpucfg_clk.common.hw, 188 }, 189 }; 190 191 static struct ccu_reset_map sun55i_a523_r_ccu_resets[] = { 192 [RST_BUS_R_TIMER] = { 0x11c, BIT(16) }, 193 [RST_BUS_R_TWD] = { 0x12c, BIT(16) }, 194 [RST_BUS_R_PWMCTRL] = { 0x13c, BIT(16) }, 195 [RST_BUS_R_SPI] = { 0x15c, BIT(16) }, 196 [RST_BUS_R_SPINLOCK] = { 0x16c, BIT(16) }, 197 [RST_BUS_R_MSGBOX] = { 0x17c, BIT(16) }, 198 [RST_BUS_R_UART0] = { 0x18c, BIT(16) }, 199 [RST_BUS_R_UART1] = { 0x18c, BIT(17) }, 200 [RST_BUS_R_I2C0] = { 0x19c, BIT(16) }, 201 [RST_BUS_R_I2C1] = { 0x19c, BIT(17) }, 202 [RST_BUS_R_I2C2] = { 0x19c, BIT(18) }, 203 [RST_BUS_R_PPU1] = { 0x1ac, BIT(17) }, 204 [RST_BUS_R_IR_RX] = { 0x1cc, BIT(16) }, 205 [RST_BUS_R_RTC] = { 0x20c, BIT(16) }, 206 [RST_BUS_R_CPUCFG] = { 0x22c, BIT(16) }, 207 }; 208 209 static const struct sunxi_ccu_desc sun55i_a523_r_ccu_desc = { 210 .ccu_clks = sun55i_a523_r_ccu_clks, 211 .num_ccu_clks = ARRAY_SIZE(sun55i_a523_r_ccu_clks), 212 213 .hw_clks = &sun55i_a523_r_hw_clks, 214 215 .resets = sun55i_a523_r_ccu_resets, 216 .num_resets = ARRAY_SIZE(sun55i_a523_r_ccu_resets), 217 }; 218 219 static int sun55i_a523_r_ccu_probe(struct platform_device *pdev) 220 { 221 void __iomem *reg; 222 223 reg = devm_platform_ioremap_resource(pdev, 0); 224 if (IS_ERR(reg)) 225 return PTR_ERR(reg); 226 227 return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun55i_a523_r_ccu_desc); 228 } 229 230 static const struct of_device_id sun55i_a523_r_ccu_ids[] = { 231 { .compatible = "allwinner,sun55i-a523-r-ccu" }, 232 { } 233 }; 234 MODULE_DEVICE_TABLE(of, sun55i_a523_r_ccu_ids); 235 236 static struct platform_driver sun55i_a523_r_ccu_driver = { 237 .probe = sun55i_a523_r_ccu_probe, 238 .driver = { 239 .name = "sun55i-a523-r-ccu", 240 .suppress_bind_attrs = true, 241 .of_match_table = sun55i_a523_r_ccu_ids, 242 }, 243 }; 244 module_platform_driver(sun55i_a523_r_ccu_driver); 245 246 MODULE_IMPORT_NS("SUNXI_CCU"); 247 MODULE_DESCRIPTION("Support for the Allwinner A523 PRCM CCU"); 248 MODULE_LICENSE("GPL"); 249