11ab4601dSManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0+ 21ab4601dSManivannan Sadhasivam /* 31ab4601dSManivannan Sadhasivam * Bitmain BM1880 SoC clock driver 41ab4601dSManivannan Sadhasivam * 51ab4601dSManivannan Sadhasivam * Copyright (c) 2019 Linaro Ltd. 61ab4601dSManivannan Sadhasivam * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 71ab4601dSManivannan Sadhasivam */ 81ab4601dSManivannan Sadhasivam 91ab4601dSManivannan Sadhasivam #include <linux/clk-provider.h> 101ab4601dSManivannan Sadhasivam #include <linux/kernel.h> 111ab4601dSManivannan Sadhasivam #include <linux/module.h> 121ab4601dSManivannan Sadhasivam #include <linux/of_address.h> 131ab4601dSManivannan Sadhasivam #include <linux/of_device.h> 141ab4601dSManivannan Sadhasivam #include <linux/platform_device.h> 151ab4601dSManivannan Sadhasivam #include <linux/slab.h> 161ab4601dSManivannan Sadhasivam 171ab4601dSManivannan Sadhasivam #include <dt-bindings/clock/bm1880-clock.h> 181ab4601dSManivannan Sadhasivam 191ab4601dSManivannan Sadhasivam #define BM1880_CLK_MPLL_CTL 0x00 201ab4601dSManivannan Sadhasivam #define BM1880_CLK_SPLL_CTL 0x04 211ab4601dSManivannan Sadhasivam #define BM1880_CLK_FPLL_CTL 0x08 221ab4601dSManivannan Sadhasivam #define BM1880_CLK_DDRPLL_CTL 0x0c 231ab4601dSManivannan Sadhasivam 241ab4601dSManivannan Sadhasivam #define BM1880_CLK_ENABLE0 0x00 251ab4601dSManivannan Sadhasivam #define BM1880_CLK_ENABLE1 0x04 261ab4601dSManivannan Sadhasivam #define BM1880_CLK_SELECT 0x20 271ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV0 0x40 281ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV1 0x44 291ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV2 0x48 301ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV3 0x4c 311ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV4 0x50 321ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV5 0x54 331ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV6 0x58 341ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV7 0x5c 351ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV8 0x60 361ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV9 0x64 371ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV10 0x68 381ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV11 0x6c 391ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV12 0x70 401ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV13 0x74 411ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV14 0x78 421ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV15 0x7c 431ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV16 0x80 441ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV17 0x84 451ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV18 0x88 461ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV19 0x8c 471ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV20 0x90 481ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV21 0x94 491ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV22 0x98 501ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV23 0x9c 511ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV24 0xa0 521ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV25 0xa4 531ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV26 0xa8 541ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV27 0xac 551ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV28 0xb0 561ab4601dSManivannan Sadhasivam 571ab4601dSManivannan Sadhasivam #define to_bm1880_pll_clk(_hw) container_of(_hw, struct bm1880_pll_hw_clock, hw) 581ab4601dSManivannan Sadhasivam #define to_bm1880_div_clk(_hw) container_of(_hw, struct bm1880_div_hw_clock, hw) 591ab4601dSManivannan Sadhasivam 601ab4601dSManivannan Sadhasivam static DEFINE_SPINLOCK(bm1880_clk_lock); 611ab4601dSManivannan Sadhasivam 621ab4601dSManivannan Sadhasivam struct bm1880_clock_data { 631ab4601dSManivannan Sadhasivam void __iomem *pll_base; 641ab4601dSManivannan Sadhasivam void __iomem *sys_base; 651ab4601dSManivannan Sadhasivam struct clk_hw_onecell_data hw_data; 661ab4601dSManivannan Sadhasivam }; 671ab4601dSManivannan Sadhasivam 681ab4601dSManivannan Sadhasivam struct bm1880_gate_clock { 691ab4601dSManivannan Sadhasivam unsigned int id; 701ab4601dSManivannan Sadhasivam const char *name; 711ab4601dSManivannan Sadhasivam const char *parent; 721ab4601dSManivannan Sadhasivam u32 gate_reg; 731ab4601dSManivannan Sadhasivam s8 gate_shift; 741ab4601dSManivannan Sadhasivam unsigned long flags; 751ab4601dSManivannan Sadhasivam }; 761ab4601dSManivannan Sadhasivam 771ab4601dSManivannan Sadhasivam struct bm1880_mux_clock { 781ab4601dSManivannan Sadhasivam unsigned int id; 791ab4601dSManivannan Sadhasivam const char *name; 801ab4601dSManivannan Sadhasivam const char * const *parents; 811ab4601dSManivannan Sadhasivam s8 num_parents; 821ab4601dSManivannan Sadhasivam u32 reg; 831ab4601dSManivannan Sadhasivam s8 shift; 841ab4601dSManivannan Sadhasivam unsigned long flags; 851ab4601dSManivannan Sadhasivam }; 861ab4601dSManivannan Sadhasivam 871ab4601dSManivannan Sadhasivam struct bm1880_div_clock { 881ab4601dSManivannan Sadhasivam unsigned int id; 891ab4601dSManivannan Sadhasivam const char *name; 901ab4601dSManivannan Sadhasivam u32 reg; 911ab4601dSManivannan Sadhasivam u8 shift; 921ab4601dSManivannan Sadhasivam u8 width; 931ab4601dSManivannan Sadhasivam u32 initval; 941ab4601dSManivannan Sadhasivam const struct clk_div_table *table; 951ab4601dSManivannan Sadhasivam unsigned long flags; 961ab4601dSManivannan Sadhasivam }; 971ab4601dSManivannan Sadhasivam 981ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock { 991ab4601dSManivannan Sadhasivam struct bm1880_div_clock div; 1001ab4601dSManivannan Sadhasivam void __iomem *base; 1011ab4601dSManivannan Sadhasivam spinlock_t *lock; 1021ab4601dSManivannan Sadhasivam struct clk_hw hw; 1031ab4601dSManivannan Sadhasivam struct clk_init_data init; 1041ab4601dSManivannan Sadhasivam }; 1051ab4601dSManivannan Sadhasivam 1061ab4601dSManivannan Sadhasivam struct bm1880_composite_clock { 1071ab4601dSManivannan Sadhasivam unsigned int id; 1081ab4601dSManivannan Sadhasivam const char *name; 1091ab4601dSManivannan Sadhasivam const char *parent; 1101ab4601dSManivannan Sadhasivam const char * const *parents; 1111ab4601dSManivannan Sadhasivam unsigned int num_parents; 1121ab4601dSManivannan Sadhasivam unsigned long flags; 1131ab4601dSManivannan Sadhasivam 1141ab4601dSManivannan Sadhasivam u32 gate_reg; 1151ab4601dSManivannan Sadhasivam u32 mux_reg; 1161ab4601dSManivannan Sadhasivam u32 div_reg; 1171ab4601dSManivannan Sadhasivam 1181ab4601dSManivannan Sadhasivam s8 gate_shift; 1191ab4601dSManivannan Sadhasivam s8 mux_shift; 1201ab4601dSManivannan Sadhasivam s8 div_shift; 1211ab4601dSManivannan Sadhasivam s8 div_width; 1221ab4601dSManivannan Sadhasivam s16 div_initval; 1231ab4601dSManivannan Sadhasivam const struct clk_div_table *table; 1241ab4601dSManivannan Sadhasivam }; 1251ab4601dSManivannan Sadhasivam 1261ab4601dSManivannan Sadhasivam struct bm1880_pll_clock { 1271ab4601dSManivannan Sadhasivam unsigned int id; 1281ab4601dSManivannan Sadhasivam const char *name; 1291ab4601dSManivannan Sadhasivam u32 reg; 1301ab4601dSManivannan Sadhasivam unsigned long flags; 1311ab4601dSManivannan Sadhasivam }; 1321ab4601dSManivannan Sadhasivam 1331ab4601dSManivannan Sadhasivam struct bm1880_pll_hw_clock { 1341ab4601dSManivannan Sadhasivam struct bm1880_pll_clock pll; 1351ab4601dSManivannan Sadhasivam void __iomem *base; 1361ab4601dSManivannan Sadhasivam struct clk_hw hw; 1371ab4601dSManivannan Sadhasivam struct clk_init_data init; 1381ab4601dSManivannan Sadhasivam }; 1391ab4601dSManivannan Sadhasivam 1401ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_pll_ops; 1411ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_clk_div_ops; 1421ab4601dSManivannan Sadhasivam 1431ab4601dSManivannan Sadhasivam #define GATE_DIV(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ 1441ab4601dSManivannan Sadhasivam _div_shift, _div_width, _div_initval, _table, \ 1451ab4601dSManivannan Sadhasivam _flags) { \ 1461ab4601dSManivannan Sadhasivam .id = _id, \ 1471ab4601dSManivannan Sadhasivam .parent = _parent, \ 1481ab4601dSManivannan Sadhasivam .name = _name, \ 1491ab4601dSManivannan Sadhasivam .gate_reg = _gate_reg, \ 1501ab4601dSManivannan Sadhasivam .gate_shift = _gate_shift, \ 1511ab4601dSManivannan Sadhasivam .div_reg = _div_reg, \ 1521ab4601dSManivannan Sadhasivam .div_shift = _div_shift, \ 1531ab4601dSManivannan Sadhasivam .div_width = _div_width, \ 1541ab4601dSManivannan Sadhasivam .div_initval = _div_initval, \ 1551ab4601dSManivannan Sadhasivam .table = _table, \ 1561ab4601dSManivannan Sadhasivam .mux_shift = -1, \ 1571ab4601dSManivannan Sadhasivam .flags = _flags, \ 1581ab4601dSManivannan Sadhasivam } 1591ab4601dSManivannan Sadhasivam 1601ab4601dSManivannan Sadhasivam #define GATE_MUX(_id, _name, _parents, _gate_reg, _gate_shift, \ 1611ab4601dSManivannan Sadhasivam _mux_reg, _mux_shift, _flags) { \ 1621ab4601dSManivannan Sadhasivam .id = _id, \ 1631ab4601dSManivannan Sadhasivam .parents = _parents, \ 1641ab4601dSManivannan Sadhasivam .num_parents = ARRAY_SIZE(_parents), \ 1651ab4601dSManivannan Sadhasivam .name = _name, \ 1661ab4601dSManivannan Sadhasivam .gate_reg = _gate_reg, \ 1671ab4601dSManivannan Sadhasivam .gate_shift = _gate_shift, \ 1681ab4601dSManivannan Sadhasivam .div_shift = -1, \ 1691ab4601dSManivannan Sadhasivam .mux_reg = _mux_reg, \ 1701ab4601dSManivannan Sadhasivam .mux_shift = _mux_shift, \ 1711ab4601dSManivannan Sadhasivam .flags = _flags, \ 1721ab4601dSManivannan Sadhasivam } 1731ab4601dSManivannan Sadhasivam 1741ab4601dSManivannan Sadhasivam #define CLK_PLL(_id, _name, _parent, _reg, _flags) { \ 1751ab4601dSManivannan Sadhasivam .pll.id = _id, \ 1761ab4601dSManivannan Sadhasivam .pll.name = _name, \ 1771ab4601dSManivannan Sadhasivam .pll.reg = _reg, \ 1781ab4601dSManivannan Sadhasivam .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, \ 1791ab4601dSManivannan Sadhasivam &bm1880_pll_ops, \ 1801ab4601dSManivannan Sadhasivam _flags), \ 1811ab4601dSManivannan Sadhasivam } 1821ab4601dSManivannan Sadhasivam 1831ab4601dSManivannan Sadhasivam #define CLK_DIV(_id, _name, _parent, _reg, _shift, _width, _initval, \ 1841ab4601dSManivannan Sadhasivam _table, _flags) { \ 1851ab4601dSManivannan Sadhasivam .div.id = _id, \ 1861ab4601dSManivannan Sadhasivam .div.name = _name, \ 1871ab4601dSManivannan Sadhasivam .div.reg = _reg, \ 1881ab4601dSManivannan Sadhasivam .div.shift = _shift, \ 1891ab4601dSManivannan Sadhasivam .div.width = _width, \ 1901ab4601dSManivannan Sadhasivam .div.initval = _initval, \ 1911ab4601dSManivannan Sadhasivam .div.table = _table, \ 1921ab4601dSManivannan Sadhasivam .hw.init = CLK_HW_INIT_HW(_name, _parent, \ 1931ab4601dSManivannan Sadhasivam &bm1880_clk_div_ops, \ 1941ab4601dSManivannan Sadhasivam _flags), \ 1951ab4601dSManivannan Sadhasivam } 1961ab4601dSManivannan Sadhasivam 1971ab4601dSManivannan Sadhasivam static struct clk_parent_data bm1880_pll_parent[] = { 1981ab4601dSManivannan Sadhasivam { .fw_name = "osc", .name = "osc" }, 1991ab4601dSManivannan Sadhasivam }; 2001ab4601dSManivannan Sadhasivam 2011ab4601dSManivannan Sadhasivam /* 2021ab4601dSManivannan Sadhasivam * All PLL clocks are marked as CRITICAL, hence they are very crucial 2031ab4601dSManivannan Sadhasivam * for the functioning of the SoC 2041ab4601dSManivannan Sadhasivam */ 2051ab4601dSManivannan Sadhasivam static struct bm1880_pll_hw_clock bm1880_pll_clks[] = { 2061ab4601dSManivannan Sadhasivam CLK_PLL(BM1880_CLK_MPLL, "clk_mpll", bm1880_pll_parent, 2071ab4601dSManivannan Sadhasivam BM1880_CLK_MPLL_CTL, 0), 2081ab4601dSManivannan Sadhasivam CLK_PLL(BM1880_CLK_SPLL, "clk_spll", bm1880_pll_parent, 2091ab4601dSManivannan Sadhasivam BM1880_CLK_SPLL_CTL, 0), 2101ab4601dSManivannan Sadhasivam CLK_PLL(BM1880_CLK_FPLL, "clk_fpll", bm1880_pll_parent, 2111ab4601dSManivannan Sadhasivam BM1880_CLK_FPLL_CTL, 0), 2121ab4601dSManivannan Sadhasivam CLK_PLL(BM1880_CLK_DDRPLL, "clk_ddrpll", bm1880_pll_parent, 2131ab4601dSManivannan Sadhasivam BM1880_CLK_DDRPLL_CTL, 0), 2141ab4601dSManivannan Sadhasivam }; 2151ab4601dSManivannan Sadhasivam 2161ab4601dSManivannan Sadhasivam /* 2171ab4601dSManivannan Sadhasivam * Clocks marked as CRITICAL are needed for the proper functioning 2181ab4601dSManivannan Sadhasivam * of the SoC. 2191ab4601dSManivannan Sadhasivam */ 2201ab4601dSManivannan Sadhasivam static const struct bm1880_gate_clock bm1880_gate_clks[] = { 2211ab4601dSManivannan Sadhasivam { BM1880_CLK_AHB_ROM, "clk_ahb_rom", "clk_mux_axi6", 2221ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 2, 0 }, 2231ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI_SRAM, "clk_axi_sram", "clk_axi1", 2241ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 3, 0 }, 2251ab4601dSManivannan Sadhasivam /* 2261ab4601dSManivannan Sadhasivam * Since this clock is sourcing the DDR memory, let's mark it as 2271ab4601dSManivannan Sadhasivam * critical to avoid gating. 2281ab4601dSManivannan Sadhasivam */ 2291ab4601dSManivannan Sadhasivam { BM1880_CLK_DDR_AXI, "clk_ddr_axi", "clk_mux_axi6", 2301ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 4, CLK_IS_CRITICAL }, 2311ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_EFUSE, "clk_apb_efuse", "clk_mux_axi6", 2321ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 6, 0 }, 2331ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI5_EMMC, "clk_axi5_emmc", "clk_axi5", 2341ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 7, 0 }, 2351ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI5_SD, "clk_axi5_sd", "clk_axi5", 2361ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 10, 0 }, 2371ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4", 2381ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 14, 0 }, 2391ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4", 2401ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 16, 0 }, 2411ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI1_GDMA, "clk_axi1_gdma", "clk_axi1", 2421ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 17, 0 }, 2431ab4601dSManivannan Sadhasivam /* Don't gate GPIO clocks as it is not owned by the GPIO driver */ 2441ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_GPIO, "clk_apb_gpio", "clk_mux_axi6", 2451ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 18, CLK_IGNORE_UNUSED }, 2461ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_mux_axi6", 2471ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 19, CLK_IGNORE_UNUSED }, 2481ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI1_MINER, "clk_axi1_miner", "clk_axi1", 2491ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 21, 0 }, 2501ab4601dSManivannan Sadhasivam { BM1880_CLK_AHB_SF, "clk_ahb_sf", "clk_mux_axi6", 2511ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 22, 0 }, 2521ab4601dSManivannan Sadhasivam /* 2531ab4601dSManivannan Sadhasivam * Not sure which module this clock is sourcing but gating this clock 2541ab4601dSManivannan Sadhasivam * prevents the system from booting. So, let's mark it as critical. 2551ab4601dSManivannan Sadhasivam */ 2561ab4601dSManivannan Sadhasivam { BM1880_CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi5", 2571ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 23, CLK_IS_CRITICAL }, 2581ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_I2C, "clk_apb_i2c", "clk_mux_axi6", 2591ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 25, 0 }, 2601ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_WDT, "clk_apb_wdt", "clk_mux_axi6", 2611ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 26, 0 }, 2621ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6", 2631ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 27, 0 }, 2641ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI5_NF, "clk_axi5_nf", "clk_axi5", 2651ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 29, 0 }, 2661ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_NF, "clk_apb_nf", "clk_axi6", 2671ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 30, 0 }, 2681ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_PWM, "clk_apb_pwm", "clk_mux_axi6", 2691ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 0, 0 }, 2701ab4601dSManivannan Sadhasivam { BM1880_CLK_RV, "clk_rv", "clk_mux_rv", 2711ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 1, 0 }, 2721ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_SPI, "clk_apb_spi", "clk_mux_axi6", 2731ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 2, 0 }, 2741ab4601dSManivannan Sadhasivam { BM1880_CLK_UART_500M, "clk_uart_500m", "clk_div_uart_500m", 2751ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 4, 0 }, 2761ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_UART, "clk_apb_uart", "clk_axi6", 2771ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 5, 0 }, 2781ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_I2S, "clk_apb_i2s", "clk_axi6", 2791ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 6, 0 }, 2801ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4", 2811ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 7, 0 }, 2821ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_USB, "clk_apb_usb", "clk_axi6", 2831ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 8, 0 }, 2841ab4601dSManivannan Sadhasivam { BM1880_CLK_12M_USB, "clk_12m_usb", "clk_div_12m_usb", 2851ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 11, 0 }, 2861ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_VIDEO, "clk_apb_video", "clk_axi6", 2871ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 12, 0 }, 2881ab4601dSManivannan Sadhasivam { BM1880_CLK_APB_VPP, "clk_apb_vpp", "clk_axi6", 2891ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 15, 0 }, 2901ab4601dSManivannan Sadhasivam { BM1880_CLK_AXI6, "clk_axi6", "clk_mux_axi6", 2911ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 21, 0 }, 2921ab4601dSManivannan Sadhasivam }; 2931ab4601dSManivannan Sadhasivam 2941ab4601dSManivannan Sadhasivam static const char * const clk_a53_parents[] = { "clk_spll", "clk_mpll" }; 2951ab4601dSManivannan Sadhasivam static const char * const clk_rv_parents[] = { "clk_div_1_rv", "clk_div_0_rv" }; 2961ab4601dSManivannan Sadhasivam static const char * const clk_axi1_parents[] = { "clk_div_1_axi1", "clk_div_0_axi1" }; 2971ab4601dSManivannan Sadhasivam static const char * const clk_axi6_parents[] = { "clk_div_1_axi6", "clk_div_0_axi6" }; 2981ab4601dSManivannan Sadhasivam 2991ab4601dSManivannan Sadhasivam static const struct bm1880_mux_clock bm1880_mux_clks[] = { 3001ab4601dSManivannan Sadhasivam { BM1880_CLK_MUX_RV, "clk_mux_rv", clk_rv_parents, 2, 3011ab4601dSManivannan Sadhasivam BM1880_CLK_SELECT, 1, 0 }, 3021ab4601dSManivannan Sadhasivam { BM1880_CLK_MUX_AXI6, "clk_mux_axi6", clk_axi6_parents, 2, 3031ab4601dSManivannan Sadhasivam BM1880_CLK_SELECT, 3, 0 }, 3041ab4601dSManivannan Sadhasivam }; 3051ab4601dSManivannan Sadhasivam 3061ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_0[] = { 3071ab4601dSManivannan Sadhasivam { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, 3081ab4601dSManivannan Sadhasivam { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, 3091ab4601dSManivannan Sadhasivam { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 }, 3101ab4601dSManivannan Sadhasivam { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 }, 3111ab4601dSManivannan Sadhasivam { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 }, 3121ab4601dSManivannan Sadhasivam { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 }, 3131ab4601dSManivannan Sadhasivam { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 }, 3141ab4601dSManivannan Sadhasivam { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 }, 3151ab4601dSManivannan Sadhasivam { 0, 0 } 3161ab4601dSManivannan Sadhasivam }; 3171ab4601dSManivannan Sadhasivam 3181ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_1[] = { 3191ab4601dSManivannan Sadhasivam { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, 3201ab4601dSManivannan Sadhasivam { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, 3211ab4601dSManivannan Sadhasivam { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 }, 3221ab4601dSManivannan Sadhasivam { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 }, 3231ab4601dSManivannan Sadhasivam { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 }, 3241ab4601dSManivannan Sadhasivam { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 }, 3251ab4601dSManivannan Sadhasivam { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 }, 3261ab4601dSManivannan Sadhasivam { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 }, 3271ab4601dSManivannan Sadhasivam { 127, 128 }, { 0, 0 } 3281ab4601dSManivannan Sadhasivam }; 3291ab4601dSManivannan Sadhasivam 3301ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_2[] = { 3311ab4601dSManivannan Sadhasivam { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, 3321ab4601dSManivannan Sadhasivam { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, 3331ab4601dSManivannan Sadhasivam { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 }, 3341ab4601dSManivannan Sadhasivam { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 }, 3351ab4601dSManivannan Sadhasivam { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 }, 3361ab4601dSManivannan Sadhasivam { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 }, 3371ab4601dSManivannan Sadhasivam { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 }, 3381ab4601dSManivannan Sadhasivam { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 }, 3391ab4601dSManivannan Sadhasivam { 127, 128 }, { 255, 256 }, { 0, 0 } 3401ab4601dSManivannan Sadhasivam }; 3411ab4601dSManivannan Sadhasivam 3421ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_3[] = { 3431ab4601dSManivannan Sadhasivam { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, 3441ab4601dSManivannan Sadhasivam { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, 3451ab4601dSManivannan Sadhasivam { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 }, 3461ab4601dSManivannan Sadhasivam { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 }, 3471ab4601dSManivannan Sadhasivam { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 }, 3481ab4601dSManivannan Sadhasivam { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 }, 3491ab4601dSManivannan Sadhasivam { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 }, 3501ab4601dSManivannan Sadhasivam { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 }, 3511ab4601dSManivannan Sadhasivam { 127, 128 }, { 255, 256 }, { 511, 512 }, { 0, 0 } 3521ab4601dSManivannan Sadhasivam }; 3531ab4601dSManivannan Sadhasivam 3541ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_4[] = { 3551ab4601dSManivannan Sadhasivam { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, 3561ab4601dSManivannan Sadhasivam { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 }, 3571ab4601dSManivannan Sadhasivam { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 }, 3581ab4601dSManivannan Sadhasivam { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 }, 3591ab4601dSManivannan Sadhasivam { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 }, 3601ab4601dSManivannan Sadhasivam { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 }, 3611ab4601dSManivannan Sadhasivam { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 }, 3621ab4601dSManivannan Sadhasivam { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 }, 3631ab4601dSManivannan Sadhasivam { 127, 128 }, { 255, 256 }, { 511, 512 }, { 65535, 65536 }, 3641ab4601dSManivannan Sadhasivam { 0, 0 } 3651ab4601dSManivannan Sadhasivam }; 3661ab4601dSManivannan Sadhasivam 3671ab4601dSManivannan Sadhasivam /* 3681ab4601dSManivannan Sadhasivam * Clocks marked as CRITICAL are needed for the proper functioning 3691ab4601dSManivannan Sadhasivam * of the SoC. 3701ab4601dSManivannan Sadhasivam */ 3711ab4601dSManivannan Sadhasivam static struct bm1880_div_hw_clock bm1880_div_clks[] = { 3721ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_0_RV, "clk_div_0_rv", &bm1880_pll_clks[1].hw, 3731ab4601dSManivannan Sadhasivam BM1880_CLK_DIV12, 16, 5, 1, bm1880_div_table_0, 0), 3741ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_1_RV, "clk_div_1_rv", &bm1880_pll_clks[2].hw, 3751ab4601dSManivannan Sadhasivam BM1880_CLK_DIV13, 16, 5, 1, bm1880_div_table_0, 0), 3761ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_UART_500M, "clk_div_uart_500m", &bm1880_pll_clks[2].hw, 3771ab4601dSManivannan Sadhasivam BM1880_CLK_DIV15, 16, 7, 3, bm1880_div_table_1, 0), 3781ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_0_AXI1, "clk_div_0_axi1", &bm1880_pll_clks[0].hw, 3791ab4601dSManivannan Sadhasivam BM1880_CLK_DIV21, 16, 5, 2, bm1880_div_table_0, 3801ab4601dSManivannan Sadhasivam 0), 3811ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_1_AXI1, "clk_div_1_axi1", &bm1880_pll_clks[2].hw, 3821ab4601dSManivannan Sadhasivam BM1880_CLK_DIV22, 16, 5, 3, bm1880_div_table_0, 3831ab4601dSManivannan Sadhasivam 0), 3841ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_0_AXI6, "clk_div_0_axi6", &bm1880_pll_clks[2].hw, 3851ab4601dSManivannan Sadhasivam BM1880_CLK_DIV27, 16, 5, 15, bm1880_div_table_0, 3861ab4601dSManivannan Sadhasivam 0), 3871ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_1_AXI6, "clk_div_1_axi6", &bm1880_pll_clks[0].hw, 3881ab4601dSManivannan Sadhasivam BM1880_CLK_DIV28, 16, 5, 11, bm1880_div_table_0, 3891ab4601dSManivannan Sadhasivam 0), 3901ab4601dSManivannan Sadhasivam CLK_DIV(BM1880_CLK_DIV_12M_USB, "clk_div_12m_usb", &bm1880_pll_clks[2].hw, 3911ab4601dSManivannan Sadhasivam BM1880_CLK_DIV18, 16, 7, 125, bm1880_div_table_1, 0), 3921ab4601dSManivannan Sadhasivam }; 3931ab4601dSManivannan Sadhasivam 3941ab4601dSManivannan Sadhasivam /* 3951ab4601dSManivannan Sadhasivam * Clocks marked as CRITICAL are all needed for the proper functioning 3961ab4601dSManivannan Sadhasivam * of the SoC. 3971ab4601dSManivannan Sadhasivam */ 3981ab4601dSManivannan Sadhasivam static struct bm1880_composite_clock bm1880_composite_clks[] = { 3991ab4601dSManivannan Sadhasivam /* 4001ab4601dSManivannan Sadhasivam * Since clk_a53 and clk_50m_a53 clocks are sourcing the CPU core, 4011ab4601dSManivannan Sadhasivam * let's mark them as critical to avoid gating. 4021ab4601dSManivannan Sadhasivam */ 4031ab4601dSManivannan Sadhasivam GATE_MUX(BM1880_CLK_A53, "clk_a53", clk_a53_parents, 4041ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 0, BM1880_CLK_SELECT, 0, 4051ab4601dSManivannan Sadhasivam CLK_IS_CRITICAL), 4061ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_50M_A53, "clk_50m_a53", "clk_fpll", 4071ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 1, BM1880_CLK_DIV0, 16, 5, 30, 4081ab4601dSManivannan Sadhasivam bm1880_div_table_0, CLK_IS_CRITICAL), 4091ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_EFUSE, "clk_efuse", "clk_fpll", 4101ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 5, BM1880_CLK_DIV1, 16, 7, 60, 4111ab4601dSManivannan Sadhasivam bm1880_div_table_1, 0), 4121ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_EMMC, "clk_emmc", "clk_fpll", 4131ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 8, BM1880_CLK_DIV2, 16, 5, 15, 4141ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4151ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_100K_EMMC, "clk_100k_emmc", "clk_div_12m_usb", 4161ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 9, BM1880_CLK_DIV3, 16, 8, 120, 4171ab4601dSManivannan Sadhasivam bm1880_div_table_2, 0), 4181ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_SD, "clk_sd", "clk_fpll", 4191ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 11, BM1880_CLK_DIV4, 16, 5, 15, 4201ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4211ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_100K_SD, "clk_100k_sd", "clk_div_12m_usb", 4221ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 12, BM1880_CLK_DIV5, 16, 8, 120, 4231ab4601dSManivannan Sadhasivam bm1880_div_table_2, 0), 4241ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_500M_ETH0, "clk_500m_eth0", "clk_fpll", 4251ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 13, BM1880_CLK_DIV6, 16, 5, 3, 4261ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4271ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_500M_ETH1, "clk_500m_eth1", "clk_fpll", 4281ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 15, BM1880_CLK_DIV7, 16, 5, 3, 4291ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4301ab4601dSManivannan Sadhasivam /* Don't gate GPIO clocks as it is not owned by the GPIO driver */ 4311ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_GPIO_DB, "clk_gpio_db", "clk_div_12m_usb", 4321ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 20, BM1880_CLK_DIV8, 16, 16, 120, 4331ab4601dSManivannan Sadhasivam bm1880_div_table_4, CLK_IGNORE_UNUSED), 4341ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_SDMA_AUD, "clk_sdma_aud", "clk_fpll", 4351ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 24, BM1880_CLK_DIV9, 16, 7, 61, 4361ab4601dSManivannan Sadhasivam bm1880_div_table_1, 0), 4371ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_JPEG_AXI, "clk_jpeg_axi", "clk_fpll", 4381ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 28, BM1880_CLK_DIV10, 16, 5, 4, 4391ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4401ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_NF, "clk_nf", "clk_fpll", 4411ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE0, 31, BM1880_CLK_DIV11, 16, 5, 30, 4421ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4431ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_TPU_AXI, "clk_tpu_axi", "clk_spll", 4441ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 3, BM1880_CLK_DIV14, 16, 5, 1, 4451ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4461ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_125M_USB, "clk_125m_usb", "clk_fpll", 4471ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 9, BM1880_CLK_DIV16, 16, 5, 12, 4481ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4491ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_33K_USB, "clk_33k_usb", "clk_div_12m_usb", 4501ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 10, BM1880_CLK_DIV17, 16, 9, 363, 4511ab4601dSManivannan Sadhasivam bm1880_div_table_3, 0), 4521ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_VIDEO_AXI, "clk_video_axi", "clk_fpll", 4531ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 13, BM1880_CLK_DIV19, 16, 5, 4, 4541ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4551ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_VPP_AXI, "clk_vpp_axi", "clk_fpll", 4561ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 14, BM1880_CLK_DIV20, 16, 5, 4, 4571ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4581ab4601dSManivannan Sadhasivam GATE_MUX(BM1880_CLK_AXI1, "clk_axi1", clk_axi1_parents, 4591ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 15, BM1880_CLK_SELECT, 2, 0), 4601ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_AXI2, "clk_axi2", "clk_fpll", 4611ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 17, BM1880_CLK_DIV23, 16, 5, 3, 4621ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4631ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_AXI3, "clk_axi3", "clk_mux_rv", 4641ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 18, BM1880_CLK_DIV24, 16, 5, 2, 4651ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4661ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_AXI4, "clk_axi4", "clk_fpll", 4671ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 19, BM1880_CLK_DIV25, 16, 5, 6, 4681ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4691ab4601dSManivannan Sadhasivam GATE_DIV(BM1880_CLK_AXI5, "clk_axi5", "clk_fpll", 4701ab4601dSManivannan Sadhasivam BM1880_CLK_ENABLE1, 20, BM1880_CLK_DIV26, 16, 5, 15, 4711ab4601dSManivannan Sadhasivam bm1880_div_table_0, 0), 4721ab4601dSManivannan Sadhasivam }; 4731ab4601dSManivannan Sadhasivam 4741ab4601dSManivannan Sadhasivam static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate) 4751ab4601dSManivannan Sadhasivam { 4761ab4601dSManivannan Sadhasivam u64 numerator; 47759ef4da4SYueHaibing u32 fbdiv, refdiv; 4781ab4601dSManivannan Sadhasivam u32 postdiv1, postdiv2, denominator; 4791ab4601dSManivannan Sadhasivam 4801ab4601dSManivannan Sadhasivam fbdiv = (regval >> 16) & 0xfff; 4811ab4601dSManivannan Sadhasivam refdiv = regval & 0x1f; 4821ab4601dSManivannan Sadhasivam postdiv1 = (regval >> 8) & 0x7; 4831ab4601dSManivannan Sadhasivam postdiv2 = (regval >> 12) & 0x7; 4841ab4601dSManivannan Sadhasivam 4851ab4601dSManivannan Sadhasivam numerator = parent_rate * fbdiv; 4861ab4601dSManivannan Sadhasivam denominator = refdiv * postdiv1 * postdiv2; 4871ab4601dSManivannan Sadhasivam do_div(numerator, denominator); 4881ab4601dSManivannan Sadhasivam 4891ab4601dSManivannan Sadhasivam return (unsigned long)numerator; 4901ab4601dSManivannan Sadhasivam } 4911ab4601dSManivannan Sadhasivam 4921ab4601dSManivannan Sadhasivam static unsigned long bm1880_pll_recalc_rate(struct clk_hw *hw, 4931ab4601dSManivannan Sadhasivam unsigned long parent_rate) 4941ab4601dSManivannan Sadhasivam { 4951ab4601dSManivannan Sadhasivam struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw); 4961ab4601dSManivannan Sadhasivam unsigned long rate; 4971ab4601dSManivannan Sadhasivam u32 regval; 4981ab4601dSManivannan Sadhasivam 4991ab4601dSManivannan Sadhasivam regval = readl(pll_hw->base + pll_hw->pll.reg); 5001ab4601dSManivannan Sadhasivam rate = bm1880_pll_rate_calc(regval, parent_rate); 5011ab4601dSManivannan Sadhasivam 5021ab4601dSManivannan Sadhasivam return rate; 5031ab4601dSManivannan Sadhasivam } 5041ab4601dSManivannan Sadhasivam 5051ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_pll_ops = { 5061ab4601dSManivannan Sadhasivam .recalc_rate = bm1880_pll_recalc_rate, 5071ab4601dSManivannan Sadhasivam }; 5081ab4601dSManivannan Sadhasivam 5091ab4601dSManivannan Sadhasivam static struct clk_hw *bm1880_clk_register_pll(struct bm1880_pll_hw_clock *pll_clk, 5101ab4601dSManivannan Sadhasivam void __iomem *sys_base) 5111ab4601dSManivannan Sadhasivam { 5121ab4601dSManivannan Sadhasivam struct clk_hw *hw; 5131ab4601dSManivannan Sadhasivam int err; 5141ab4601dSManivannan Sadhasivam 5151ab4601dSManivannan Sadhasivam pll_clk->base = sys_base; 5161ab4601dSManivannan Sadhasivam hw = &pll_clk->hw; 5171ab4601dSManivannan Sadhasivam 5181ab4601dSManivannan Sadhasivam err = clk_hw_register(NULL, hw); 5191ab4601dSManivannan Sadhasivam if (err) 5201ab4601dSManivannan Sadhasivam return ERR_PTR(err); 5211ab4601dSManivannan Sadhasivam 5221ab4601dSManivannan Sadhasivam return hw; 5231ab4601dSManivannan Sadhasivam } 5241ab4601dSManivannan Sadhasivam 5251ab4601dSManivannan Sadhasivam static int bm1880_clk_register_plls(struct bm1880_pll_hw_clock *clks, 5261ab4601dSManivannan Sadhasivam int num_clks, 5271ab4601dSManivannan Sadhasivam struct bm1880_clock_data *data) 5281ab4601dSManivannan Sadhasivam { 5291ab4601dSManivannan Sadhasivam struct clk_hw *hw; 5301ab4601dSManivannan Sadhasivam void __iomem *pll_base = data->pll_base; 5311ab4601dSManivannan Sadhasivam int i; 5321ab4601dSManivannan Sadhasivam 5331ab4601dSManivannan Sadhasivam for (i = 0; i < num_clks; i++) { 5341ab4601dSManivannan Sadhasivam struct bm1880_pll_hw_clock *bm1880_clk = &clks[i]; 5351ab4601dSManivannan Sadhasivam 5361ab4601dSManivannan Sadhasivam hw = bm1880_clk_register_pll(bm1880_clk, pll_base); 5371ab4601dSManivannan Sadhasivam if (IS_ERR(hw)) { 5381ab4601dSManivannan Sadhasivam pr_err("%s: failed to register clock %s\n", 5391ab4601dSManivannan Sadhasivam __func__, bm1880_clk->pll.name); 5401ab4601dSManivannan Sadhasivam goto err_clk; 5411ab4601dSManivannan Sadhasivam } 5421ab4601dSManivannan Sadhasivam 5431ab4601dSManivannan Sadhasivam data->hw_data.hws[clks[i].pll.id] = hw; 5441ab4601dSManivannan Sadhasivam } 5451ab4601dSManivannan Sadhasivam 5461ab4601dSManivannan Sadhasivam return 0; 5471ab4601dSManivannan Sadhasivam 5481ab4601dSManivannan Sadhasivam err_clk: 5491ab4601dSManivannan Sadhasivam while (i--) 550*c861c1beSConor Dooley clk_hw_unregister(data->hw_data.hws[clks[i].pll.id]); 5511ab4601dSManivannan Sadhasivam 5521ab4601dSManivannan Sadhasivam return PTR_ERR(hw); 5531ab4601dSManivannan Sadhasivam } 5541ab4601dSManivannan Sadhasivam 5551ab4601dSManivannan Sadhasivam static int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks, 5561ab4601dSManivannan Sadhasivam int num_clks, 5571ab4601dSManivannan Sadhasivam struct bm1880_clock_data *data) 5581ab4601dSManivannan Sadhasivam { 5591ab4601dSManivannan Sadhasivam struct clk_hw *hw; 5601ab4601dSManivannan Sadhasivam void __iomem *sys_base = data->sys_base; 5611ab4601dSManivannan Sadhasivam int i; 5621ab4601dSManivannan Sadhasivam 5631ab4601dSManivannan Sadhasivam for (i = 0; i < num_clks; i++) { 5641ab4601dSManivannan Sadhasivam hw = clk_hw_register_mux(NULL, clks[i].name, 5651ab4601dSManivannan Sadhasivam clks[i].parents, 5661ab4601dSManivannan Sadhasivam clks[i].num_parents, 5671ab4601dSManivannan Sadhasivam clks[i].flags, 5681ab4601dSManivannan Sadhasivam sys_base + clks[i].reg, 5691ab4601dSManivannan Sadhasivam clks[i].shift, 1, 0, 5701ab4601dSManivannan Sadhasivam &bm1880_clk_lock); 5711ab4601dSManivannan Sadhasivam if (IS_ERR(hw)) { 5721ab4601dSManivannan Sadhasivam pr_err("%s: failed to register clock %s\n", 5731ab4601dSManivannan Sadhasivam __func__, clks[i].name); 5741ab4601dSManivannan Sadhasivam goto err_clk; 5751ab4601dSManivannan Sadhasivam } 5761ab4601dSManivannan Sadhasivam 5771ab4601dSManivannan Sadhasivam data->hw_data.hws[clks[i].id] = hw; 5781ab4601dSManivannan Sadhasivam } 5791ab4601dSManivannan Sadhasivam 5801ab4601dSManivannan Sadhasivam return 0; 5811ab4601dSManivannan Sadhasivam 5821ab4601dSManivannan Sadhasivam err_clk: 5831ab4601dSManivannan Sadhasivam while (i--) 5841ab4601dSManivannan Sadhasivam clk_hw_unregister_mux(data->hw_data.hws[clks[i].id]); 5851ab4601dSManivannan Sadhasivam 5861ab4601dSManivannan Sadhasivam return PTR_ERR(hw); 5871ab4601dSManivannan Sadhasivam } 5881ab4601dSManivannan Sadhasivam 5891ab4601dSManivannan Sadhasivam static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw, 5901ab4601dSManivannan Sadhasivam unsigned long parent_rate) 5911ab4601dSManivannan Sadhasivam { 5921ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw); 5931ab4601dSManivannan Sadhasivam struct bm1880_div_clock *div = &div_hw->div; 5941ab4601dSManivannan Sadhasivam void __iomem *reg_addr = div_hw->base + div->reg; 5951ab4601dSManivannan Sadhasivam unsigned int val; 5961ab4601dSManivannan Sadhasivam unsigned long rate; 5971ab4601dSManivannan Sadhasivam 5981ab4601dSManivannan Sadhasivam if (!(readl(reg_addr) & BIT(3))) { 5991ab4601dSManivannan Sadhasivam val = div->initval; 6001ab4601dSManivannan Sadhasivam } else { 6011ab4601dSManivannan Sadhasivam val = readl(reg_addr) >> div->shift; 6021ab4601dSManivannan Sadhasivam val &= clk_div_mask(div->width); 6031ab4601dSManivannan Sadhasivam } 6041ab4601dSManivannan Sadhasivam 6051ab4601dSManivannan Sadhasivam rate = divider_recalc_rate(hw, parent_rate, val, div->table, 6061ab4601dSManivannan Sadhasivam div->flags, div->width); 6071ab4601dSManivannan Sadhasivam 6081ab4601dSManivannan Sadhasivam return rate; 6091ab4601dSManivannan Sadhasivam } 6101ab4601dSManivannan Sadhasivam 6111ab4601dSManivannan Sadhasivam static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, 6121ab4601dSManivannan Sadhasivam unsigned long *prate) 6131ab4601dSManivannan Sadhasivam { 6141ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw); 6151ab4601dSManivannan Sadhasivam struct bm1880_div_clock *div = &div_hw->div; 6161ab4601dSManivannan Sadhasivam void __iomem *reg_addr = div_hw->base + div->reg; 6171ab4601dSManivannan Sadhasivam 6181ab4601dSManivannan Sadhasivam if (div->flags & CLK_DIVIDER_READ_ONLY) { 6191ab4601dSManivannan Sadhasivam u32 val; 6201ab4601dSManivannan Sadhasivam 6211ab4601dSManivannan Sadhasivam val = readl(reg_addr) >> div->shift; 6221ab4601dSManivannan Sadhasivam val &= clk_div_mask(div->width); 6231ab4601dSManivannan Sadhasivam 6241ab4601dSManivannan Sadhasivam return divider_ro_round_rate(hw, rate, prate, div->table, 6251ab4601dSManivannan Sadhasivam div->width, div->flags, 6261ab4601dSManivannan Sadhasivam val); 6271ab4601dSManivannan Sadhasivam } 6281ab4601dSManivannan Sadhasivam 6291ab4601dSManivannan Sadhasivam return divider_round_rate(hw, rate, prate, div->table, 6301ab4601dSManivannan Sadhasivam div->width, div->flags); 6311ab4601dSManivannan Sadhasivam } 6321ab4601dSManivannan Sadhasivam 6331ab4601dSManivannan Sadhasivam static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, 6341ab4601dSManivannan Sadhasivam unsigned long parent_rate) 6351ab4601dSManivannan Sadhasivam { 6361ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw); 6371ab4601dSManivannan Sadhasivam struct bm1880_div_clock *div = &div_hw->div; 6381ab4601dSManivannan Sadhasivam void __iomem *reg_addr = div_hw->base + div->reg; 6391ab4601dSManivannan Sadhasivam unsigned long flags = 0; 6401ab4601dSManivannan Sadhasivam int value; 6411ab4601dSManivannan Sadhasivam u32 val; 6421ab4601dSManivannan Sadhasivam 6431ab4601dSManivannan Sadhasivam value = divider_get_val(rate, parent_rate, div->table, 6441ab4601dSManivannan Sadhasivam div->width, div_hw->div.flags); 6451ab4601dSManivannan Sadhasivam if (value < 0) 6461ab4601dSManivannan Sadhasivam return value; 6471ab4601dSManivannan Sadhasivam 6481ab4601dSManivannan Sadhasivam if (div_hw->lock) 6491ab4601dSManivannan Sadhasivam spin_lock_irqsave(div_hw->lock, flags); 6501ab4601dSManivannan Sadhasivam else 6511ab4601dSManivannan Sadhasivam __acquire(div_hw->lock); 6521ab4601dSManivannan Sadhasivam 6531ab4601dSManivannan Sadhasivam val = readl(reg_addr); 6541ab4601dSManivannan Sadhasivam val &= ~(clk_div_mask(div->width) << div_hw->div.shift); 6551ab4601dSManivannan Sadhasivam val |= (u32)value << div->shift; 6561ab4601dSManivannan Sadhasivam writel(val, reg_addr); 6571ab4601dSManivannan Sadhasivam 6581ab4601dSManivannan Sadhasivam if (div_hw->lock) 6591ab4601dSManivannan Sadhasivam spin_unlock_irqrestore(div_hw->lock, flags); 6601ab4601dSManivannan Sadhasivam else 6611ab4601dSManivannan Sadhasivam __release(div_hw->lock); 6621ab4601dSManivannan Sadhasivam 6631ab4601dSManivannan Sadhasivam return 0; 6641ab4601dSManivannan Sadhasivam } 6651ab4601dSManivannan Sadhasivam 6661ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_clk_div_ops = { 6671ab4601dSManivannan Sadhasivam .recalc_rate = bm1880_clk_div_recalc_rate, 6681ab4601dSManivannan Sadhasivam .round_rate = bm1880_clk_div_round_rate, 6691ab4601dSManivannan Sadhasivam .set_rate = bm1880_clk_div_set_rate, 6701ab4601dSManivannan Sadhasivam }; 6711ab4601dSManivannan Sadhasivam 6721ab4601dSManivannan Sadhasivam static struct clk_hw *bm1880_clk_register_div(struct bm1880_div_hw_clock *div_clk, 6731ab4601dSManivannan Sadhasivam void __iomem *sys_base) 6741ab4601dSManivannan Sadhasivam { 6751ab4601dSManivannan Sadhasivam struct clk_hw *hw; 6761ab4601dSManivannan Sadhasivam int err; 6771ab4601dSManivannan Sadhasivam 6781ab4601dSManivannan Sadhasivam div_clk->div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; 6791ab4601dSManivannan Sadhasivam div_clk->base = sys_base; 6801ab4601dSManivannan Sadhasivam div_clk->lock = &bm1880_clk_lock; 6811ab4601dSManivannan Sadhasivam 6821ab4601dSManivannan Sadhasivam hw = &div_clk->hw; 6831ab4601dSManivannan Sadhasivam err = clk_hw_register(NULL, hw); 6841ab4601dSManivannan Sadhasivam if (err) 6851ab4601dSManivannan Sadhasivam return ERR_PTR(err); 6861ab4601dSManivannan Sadhasivam 6871ab4601dSManivannan Sadhasivam return hw; 6881ab4601dSManivannan Sadhasivam } 6891ab4601dSManivannan Sadhasivam 6901ab4601dSManivannan Sadhasivam static int bm1880_clk_register_divs(struct bm1880_div_hw_clock *clks, 6911ab4601dSManivannan Sadhasivam int num_clks, 6921ab4601dSManivannan Sadhasivam struct bm1880_clock_data *data) 6931ab4601dSManivannan Sadhasivam { 6941ab4601dSManivannan Sadhasivam struct clk_hw *hw; 6951ab4601dSManivannan Sadhasivam void __iomem *sys_base = data->sys_base; 6961ab4601dSManivannan Sadhasivam unsigned int i, id; 6971ab4601dSManivannan Sadhasivam 6981ab4601dSManivannan Sadhasivam for (i = 0; i < num_clks; i++) { 6991ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock *bm1880_clk = &clks[i]; 7001ab4601dSManivannan Sadhasivam 7011ab4601dSManivannan Sadhasivam hw = bm1880_clk_register_div(bm1880_clk, sys_base); 7021ab4601dSManivannan Sadhasivam if (IS_ERR(hw)) { 7031ab4601dSManivannan Sadhasivam pr_err("%s: failed to register clock %s\n", 7041ab4601dSManivannan Sadhasivam __func__, bm1880_clk->div.name); 7051ab4601dSManivannan Sadhasivam goto err_clk; 7061ab4601dSManivannan Sadhasivam } 7071ab4601dSManivannan Sadhasivam 7081ab4601dSManivannan Sadhasivam id = clks[i].div.id; 7091ab4601dSManivannan Sadhasivam data->hw_data.hws[id] = hw; 7101ab4601dSManivannan Sadhasivam } 7111ab4601dSManivannan Sadhasivam 7121ab4601dSManivannan Sadhasivam return 0; 7131ab4601dSManivannan Sadhasivam 7141ab4601dSManivannan Sadhasivam err_clk: 7151ab4601dSManivannan Sadhasivam while (i--) 716*c861c1beSConor Dooley clk_hw_unregister(data->hw_data.hws[clks[i].div.id]); 7171ab4601dSManivannan Sadhasivam 7181ab4601dSManivannan Sadhasivam return PTR_ERR(hw); 7191ab4601dSManivannan Sadhasivam } 7201ab4601dSManivannan Sadhasivam 7211ab4601dSManivannan Sadhasivam static int bm1880_clk_register_gate(const struct bm1880_gate_clock *clks, 7221ab4601dSManivannan Sadhasivam int num_clks, 7231ab4601dSManivannan Sadhasivam struct bm1880_clock_data *data) 7241ab4601dSManivannan Sadhasivam { 7251ab4601dSManivannan Sadhasivam struct clk_hw *hw; 7261ab4601dSManivannan Sadhasivam void __iomem *sys_base = data->sys_base; 7271ab4601dSManivannan Sadhasivam int i; 7281ab4601dSManivannan Sadhasivam 7291ab4601dSManivannan Sadhasivam for (i = 0; i < num_clks; i++) { 7301ab4601dSManivannan Sadhasivam hw = clk_hw_register_gate(NULL, clks[i].name, 7311ab4601dSManivannan Sadhasivam clks[i].parent, 7321ab4601dSManivannan Sadhasivam clks[i].flags, 7331ab4601dSManivannan Sadhasivam sys_base + clks[i].gate_reg, 7341ab4601dSManivannan Sadhasivam clks[i].gate_shift, 0, 7351ab4601dSManivannan Sadhasivam &bm1880_clk_lock); 7361ab4601dSManivannan Sadhasivam if (IS_ERR(hw)) { 7371ab4601dSManivannan Sadhasivam pr_err("%s: failed to register clock %s\n", 7381ab4601dSManivannan Sadhasivam __func__, clks[i].name); 7391ab4601dSManivannan Sadhasivam goto err_clk; 7401ab4601dSManivannan Sadhasivam } 7411ab4601dSManivannan Sadhasivam 7421ab4601dSManivannan Sadhasivam data->hw_data.hws[clks[i].id] = hw; 7431ab4601dSManivannan Sadhasivam } 7441ab4601dSManivannan Sadhasivam 7451ab4601dSManivannan Sadhasivam return 0; 7461ab4601dSManivannan Sadhasivam 7471ab4601dSManivannan Sadhasivam err_clk: 7481ab4601dSManivannan Sadhasivam while (i--) 7491ab4601dSManivannan Sadhasivam clk_hw_unregister_gate(data->hw_data.hws[clks[i].id]); 7501ab4601dSManivannan Sadhasivam 7511ab4601dSManivannan Sadhasivam return PTR_ERR(hw); 7521ab4601dSManivannan Sadhasivam } 7531ab4601dSManivannan Sadhasivam 7541ab4601dSManivannan Sadhasivam static struct clk_hw *bm1880_clk_register_composite(struct bm1880_composite_clock *clks, 7551ab4601dSManivannan Sadhasivam void __iomem *sys_base) 7561ab4601dSManivannan Sadhasivam { 7571ab4601dSManivannan Sadhasivam struct clk_hw *hw; 7581ab4601dSManivannan Sadhasivam struct clk_mux *mux = NULL; 7591ab4601dSManivannan Sadhasivam struct clk_gate *gate = NULL; 7601ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock *div_hws = NULL; 7611ab4601dSManivannan Sadhasivam struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL; 7621ab4601dSManivannan Sadhasivam const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL; 7631ab4601dSManivannan Sadhasivam const char * const *parent_names; 7641ab4601dSManivannan Sadhasivam const char *parent; 7651ab4601dSManivannan Sadhasivam int num_parents; 7661ab4601dSManivannan Sadhasivam int ret; 7671ab4601dSManivannan Sadhasivam 7681ab4601dSManivannan Sadhasivam if (clks->mux_shift >= 0) { 7691ab4601dSManivannan Sadhasivam mux = kzalloc(sizeof(*mux), GFP_KERNEL); 7701ab4601dSManivannan Sadhasivam if (!mux) 7711ab4601dSManivannan Sadhasivam return ERR_PTR(-ENOMEM); 7721ab4601dSManivannan Sadhasivam 7731ab4601dSManivannan Sadhasivam mux->reg = sys_base + clks->mux_reg; 7741ab4601dSManivannan Sadhasivam mux->mask = 1; 7751ab4601dSManivannan Sadhasivam mux->shift = clks->mux_shift; 7761ab4601dSManivannan Sadhasivam mux_hw = &mux->hw; 7771ab4601dSManivannan Sadhasivam mux_ops = &clk_mux_ops; 7781ab4601dSManivannan Sadhasivam mux->lock = &bm1880_clk_lock; 7791ab4601dSManivannan Sadhasivam 7801ab4601dSManivannan Sadhasivam parent_names = clks->parents; 7811ab4601dSManivannan Sadhasivam num_parents = clks->num_parents; 7821ab4601dSManivannan Sadhasivam } else { 7831ab4601dSManivannan Sadhasivam parent = clks->parent; 7841ab4601dSManivannan Sadhasivam parent_names = &parent; 7851ab4601dSManivannan Sadhasivam num_parents = 1; 7861ab4601dSManivannan Sadhasivam } 7871ab4601dSManivannan Sadhasivam 7881ab4601dSManivannan Sadhasivam if (clks->gate_shift >= 0) { 7891ab4601dSManivannan Sadhasivam gate = kzalloc(sizeof(*gate), GFP_KERNEL); 7901ab4601dSManivannan Sadhasivam if (!gate) { 7911ab4601dSManivannan Sadhasivam ret = -ENOMEM; 7921ab4601dSManivannan Sadhasivam goto err_out; 7931ab4601dSManivannan Sadhasivam } 7941ab4601dSManivannan Sadhasivam 7951ab4601dSManivannan Sadhasivam gate->reg = sys_base + clks->gate_reg; 7961ab4601dSManivannan Sadhasivam gate->bit_idx = clks->gate_shift; 7971ab4601dSManivannan Sadhasivam gate->lock = &bm1880_clk_lock; 7981ab4601dSManivannan Sadhasivam 7991ab4601dSManivannan Sadhasivam gate_hw = &gate->hw; 8001ab4601dSManivannan Sadhasivam gate_ops = &clk_gate_ops; 8011ab4601dSManivannan Sadhasivam } 8021ab4601dSManivannan Sadhasivam 8031ab4601dSManivannan Sadhasivam if (clks->div_shift >= 0) { 8041ab4601dSManivannan Sadhasivam div_hws = kzalloc(sizeof(*div_hws), GFP_KERNEL); 8051ab4601dSManivannan Sadhasivam if (!div_hws) { 8061ab4601dSManivannan Sadhasivam ret = -ENOMEM; 8071ab4601dSManivannan Sadhasivam goto err_out; 8081ab4601dSManivannan Sadhasivam } 8091ab4601dSManivannan Sadhasivam 8101ab4601dSManivannan Sadhasivam div_hws->base = sys_base; 8111ab4601dSManivannan Sadhasivam div_hws->div.reg = clks->div_reg; 8121ab4601dSManivannan Sadhasivam div_hws->div.shift = clks->div_shift; 8131ab4601dSManivannan Sadhasivam div_hws->div.width = clks->div_width; 8141ab4601dSManivannan Sadhasivam div_hws->div.table = clks->table; 8151ab4601dSManivannan Sadhasivam div_hws->div.initval = clks->div_initval; 8161ab4601dSManivannan Sadhasivam div_hws->lock = &bm1880_clk_lock; 8171ab4601dSManivannan Sadhasivam div_hws->div.flags = CLK_DIVIDER_ONE_BASED | 8181ab4601dSManivannan Sadhasivam CLK_DIVIDER_ALLOW_ZERO; 8191ab4601dSManivannan Sadhasivam 8201ab4601dSManivannan Sadhasivam div_hw = &div_hws->hw; 8211ab4601dSManivannan Sadhasivam div_ops = &bm1880_clk_div_ops; 8221ab4601dSManivannan Sadhasivam } 8231ab4601dSManivannan Sadhasivam 8241ab4601dSManivannan Sadhasivam hw = clk_hw_register_composite(NULL, clks->name, parent_names, 8251ab4601dSManivannan Sadhasivam num_parents, mux_hw, mux_ops, div_hw, 8261ab4601dSManivannan Sadhasivam div_ops, gate_hw, gate_ops, 8271ab4601dSManivannan Sadhasivam clks->flags); 8281ab4601dSManivannan Sadhasivam 8291ab4601dSManivannan Sadhasivam if (IS_ERR(hw)) { 8301ab4601dSManivannan Sadhasivam ret = PTR_ERR(hw); 8311ab4601dSManivannan Sadhasivam goto err_out; 8321ab4601dSManivannan Sadhasivam } 8331ab4601dSManivannan Sadhasivam 8341ab4601dSManivannan Sadhasivam return hw; 8351ab4601dSManivannan Sadhasivam 8361ab4601dSManivannan Sadhasivam err_out: 8371ab4601dSManivannan Sadhasivam kfree(div_hws); 8381ab4601dSManivannan Sadhasivam kfree(gate); 8391ab4601dSManivannan Sadhasivam kfree(mux); 8401ab4601dSManivannan Sadhasivam 8411ab4601dSManivannan Sadhasivam return ERR_PTR(ret); 8421ab4601dSManivannan Sadhasivam } 8431ab4601dSManivannan Sadhasivam 8441ab4601dSManivannan Sadhasivam static int bm1880_clk_register_composites(struct bm1880_composite_clock *clks, 8451ab4601dSManivannan Sadhasivam int num_clks, 8461ab4601dSManivannan Sadhasivam struct bm1880_clock_data *data) 8471ab4601dSManivannan Sadhasivam { 8481ab4601dSManivannan Sadhasivam struct clk_hw *hw; 8491ab4601dSManivannan Sadhasivam void __iomem *sys_base = data->sys_base; 8501ab4601dSManivannan Sadhasivam int i; 8511ab4601dSManivannan Sadhasivam 8521ab4601dSManivannan Sadhasivam for (i = 0; i < num_clks; i++) { 8531ab4601dSManivannan Sadhasivam struct bm1880_composite_clock *bm1880_clk = &clks[i]; 8541ab4601dSManivannan Sadhasivam 8551ab4601dSManivannan Sadhasivam hw = bm1880_clk_register_composite(bm1880_clk, sys_base); 8561ab4601dSManivannan Sadhasivam if (IS_ERR(hw)) { 8571ab4601dSManivannan Sadhasivam pr_err("%s: failed to register clock %s\n", 8581ab4601dSManivannan Sadhasivam __func__, bm1880_clk->name); 8591ab4601dSManivannan Sadhasivam goto err_clk; 8601ab4601dSManivannan Sadhasivam } 8611ab4601dSManivannan Sadhasivam 8621ab4601dSManivannan Sadhasivam data->hw_data.hws[clks[i].id] = hw; 8631ab4601dSManivannan Sadhasivam } 8641ab4601dSManivannan Sadhasivam 8651ab4601dSManivannan Sadhasivam return 0; 8661ab4601dSManivannan Sadhasivam 8671ab4601dSManivannan Sadhasivam err_clk: 8681ab4601dSManivannan Sadhasivam while (i--) 8691ab4601dSManivannan Sadhasivam clk_hw_unregister_composite(data->hw_data.hws[clks[i].id]); 8701ab4601dSManivannan Sadhasivam 8711ab4601dSManivannan Sadhasivam return PTR_ERR(hw); 8721ab4601dSManivannan Sadhasivam } 8731ab4601dSManivannan Sadhasivam 8741ab4601dSManivannan Sadhasivam static int bm1880_clk_probe(struct platform_device *pdev) 8751ab4601dSManivannan Sadhasivam { 8761ab4601dSManivannan Sadhasivam struct bm1880_clock_data *clk_data; 8771ab4601dSManivannan Sadhasivam void __iomem *pll_base, *sys_base; 8781ab4601dSManivannan Sadhasivam struct device *dev = &pdev->dev; 8791ab4601dSManivannan Sadhasivam struct resource *res; 8801ab4601dSManivannan Sadhasivam int num_clks, i; 8811ab4601dSManivannan Sadhasivam 8821ab4601dSManivannan Sadhasivam res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 8831ab4601dSManivannan Sadhasivam pll_base = devm_ioremap_resource(&pdev->dev, res); 8841ab4601dSManivannan Sadhasivam if (IS_ERR(pll_base)) 8851ab4601dSManivannan Sadhasivam return PTR_ERR(pll_base); 8861ab4601dSManivannan Sadhasivam 8871ab4601dSManivannan Sadhasivam res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 8881ab4601dSManivannan Sadhasivam sys_base = devm_ioremap_resource(&pdev->dev, res); 8891ab4601dSManivannan Sadhasivam if (IS_ERR(sys_base)) 8901ab4601dSManivannan Sadhasivam return PTR_ERR(sys_base); 8911ab4601dSManivannan Sadhasivam 8921ab4601dSManivannan Sadhasivam num_clks = ARRAY_SIZE(bm1880_pll_clks) + 8931ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_div_clks) + 8941ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_mux_clks) + 8951ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_composite_clks) + 8961ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_gate_clks); 8971ab4601dSManivannan Sadhasivam 8981ab4601dSManivannan Sadhasivam clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, 8991ab4601dSManivannan Sadhasivam num_clks), GFP_KERNEL); 9001ab4601dSManivannan Sadhasivam if (!clk_data) 9011ab4601dSManivannan Sadhasivam return -ENOMEM; 9021ab4601dSManivannan Sadhasivam 9031ab4601dSManivannan Sadhasivam clk_data->pll_base = pll_base; 9041ab4601dSManivannan Sadhasivam clk_data->sys_base = sys_base; 9051ab4601dSManivannan Sadhasivam 9061ab4601dSManivannan Sadhasivam for (i = 0; i < num_clks; i++) 9071ab4601dSManivannan Sadhasivam clk_data->hw_data.hws[i] = ERR_PTR(-ENOENT); 9081ab4601dSManivannan Sadhasivam 9091ab4601dSManivannan Sadhasivam clk_data->hw_data.num = num_clks; 9101ab4601dSManivannan Sadhasivam 9111ab4601dSManivannan Sadhasivam bm1880_clk_register_plls(bm1880_pll_clks, 9121ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_pll_clks), 9131ab4601dSManivannan Sadhasivam clk_data); 9141ab4601dSManivannan Sadhasivam 9151ab4601dSManivannan Sadhasivam bm1880_clk_register_divs(bm1880_div_clks, 9161ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_div_clks), 9171ab4601dSManivannan Sadhasivam clk_data); 9181ab4601dSManivannan Sadhasivam 9191ab4601dSManivannan Sadhasivam bm1880_clk_register_mux(bm1880_mux_clks, 9201ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_mux_clks), 9211ab4601dSManivannan Sadhasivam clk_data); 9221ab4601dSManivannan Sadhasivam 9231ab4601dSManivannan Sadhasivam bm1880_clk_register_composites(bm1880_composite_clks, 9241ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_composite_clks), 9251ab4601dSManivannan Sadhasivam clk_data); 9261ab4601dSManivannan Sadhasivam 9271ab4601dSManivannan Sadhasivam bm1880_clk_register_gate(bm1880_gate_clks, 9281ab4601dSManivannan Sadhasivam ARRAY_SIZE(bm1880_gate_clks), 9291ab4601dSManivannan Sadhasivam clk_data); 9301ab4601dSManivannan Sadhasivam 9311ab4601dSManivannan Sadhasivam return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, 9321ab4601dSManivannan Sadhasivam &clk_data->hw_data); 9331ab4601dSManivannan Sadhasivam } 9341ab4601dSManivannan Sadhasivam 9351ab4601dSManivannan Sadhasivam static const struct of_device_id bm1880_of_match[] = { 9361ab4601dSManivannan Sadhasivam { .compatible = "bitmain,bm1880-clk", }, 9371ab4601dSManivannan Sadhasivam {} 9381ab4601dSManivannan Sadhasivam }; 9391ab4601dSManivannan Sadhasivam MODULE_DEVICE_TABLE(of, bm1880_of_match); 9401ab4601dSManivannan Sadhasivam 9411ab4601dSManivannan Sadhasivam static struct platform_driver bm1880_clk_driver = { 9421ab4601dSManivannan Sadhasivam .driver = { 9431ab4601dSManivannan Sadhasivam .name = "bm1880-clk", 9441ab4601dSManivannan Sadhasivam .of_match_table = bm1880_of_match, 9451ab4601dSManivannan Sadhasivam }, 9461ab4601dSManivannan Sadhasivam .probe = bm1880_clk_probe, 9471ab4601dSManivannan Sadhasivam }; 9481ab4601dSManivannan Sadhasivam module_platform_driver(bm1880_clk_driver); 9491ab4601dSManivannan Sadhasivam 9501ab4601dSManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 9511ab4601dSManivannan Sadhasivam MODULE_DESCRIPTION("Clock driver for Bitmain BM1880 SoC"); 9521ab4601dSManivannan Sadhasivam MODULE_LICENSE("GPL v2"); 953