1*1e3121bfSAisheng Dong // SPDX-License-Identifier: GPL-2.0+ 2*1e3121bfSAisheng Dong /* 3*1e3121bfSAisheng Dong * Copyright 2018 NXP 4*1e3121bfSAisheng Dong * Dong Aisheng <aisheng.dong@nxp.com> 5*1e3121bfSAisheng Dong */ 6*1e3121bfSAisheng Dong 7*1e3121bfSAisheng Dong #include <linux/clk-provider.h> 8*1e3121bfSAisheng Dong #include <linux/err.h> 9*1e3121bfSAisheng Dong #include <linux/io.h> 10*1e3121bfSAisheng Dong #include <linux/module.h> 11*1e3121bfSAisheng Dong #include <linux/of.h> 12*1e3121bfSAisheng Dong #include <linux/of_device.h> 13*1e3121bfSAisheng Dong #include <linux/platform_device.h> 14*1e3121bfSAisheng Dong #include <linux/slab.h> 15*1e3121bfSAisheng Dong 16*1e3121bfSAisheng Dong #include "clk-scu.h" 17*1e3121bfSAisheng Dong #include "clk-imx8qxp-lpcg.h" 18*1e3121bfSAisheng Dong 19*1e3121bfSAisheng Dong #include <dt-bindings/clock/imx8qxp-clock.h> 20*1e3121bfSAisheng Dong 21*1e3121bfSAisheng Dong /* 22*1e3121bfSAisheng Dong * struct imx8qxp_lpcg_data - Description of one LPCG clock 23*1e3121bfSAisheng Dong * @id: clock ID 24*1e3121bfSAisheng Dong * @name: clock name 25*1e3121bfSAisheng Dong * @parent: parent clock name 26*1e3121bfSAisheng Dong * @flags: common clock flags 27*1e3121bfSAisheng Dong * @offset: offset of this LPCG clock 28*1e3121bfSAisheng Dong * @bit_idx: bit index of this LPCG clock 29*1e3121bfSAisheng Dong * @hw_gate: whether supports HW autogate 30*1e3121bfSAisheng Dong * 31*1e3121bfSAisheng Dong * This structure describes one LPCG clock 32*1e3121bfSAisheng Dong */ 33*1e3121bfSAisheng Dong struct imx8qxp_lpcg_data { 34*1e3121bfSAisheng Dong int id; 35*1e3121bfSAisheng Dong char *name; 36*1e3121bfSAisheng Dong char *parent; 37*1e3121bfSAisheng Dong unsigned long flags; 38*1e3121bfSAisheng Dong u32 offset; 39*1e3121bfSAisheng Dong u8 bit_idx; 40*1e3121bfSAisheng Dong bool hw_gate; 41*1e3121bfSAisheng Dong }; 42*1e3121bfSAisheng Dong 43*1e3121bfSAisheng Dong /* 44*1e3121bfSAisheng Dong * struct imx8qxp_ss_lpcg - Description of one subsystem LPCG clocks 45*1e3121bfSAisheng Dong * @lpcg: LPCG clocks array of one subsystem 46*1e3121bfSAisheng Dong * @num_lpcg: the number of LPCG clocks 47*1e3121bfSAisheng Dong * @num_max: the maximum number of LPCG clocks 48*1e3121bfSAisheng Dong * 49*1e3121bfSAisheng Dong * This structure describes each subsystem LPCG clocks information 50*1e3121bfSAisheng Dong * which then will be used to create respective LPCGs clocks 51*1e3121bfSAisheng Dong */ 52*1e3121bfSAisheng Dong struct imx8qxp_ss_lpcg { 53*1e3121bfSAisheng Dong const struct imx8qxp_lpcg_data *lpcg; 54*1e3121bfSAisheng Dong u8 num_lpcg; 55*1e3121bfSAisheng Dong u8 num_max; 56*1e3121bfSAisheng Dong }; 57*1e3121bfSAisheng Dong 58*1e3121bfSAisheng Dong static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = { 59*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, }, 60*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, }, 61*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, }, 62*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, }, 63*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART2_IPG_CLK, "uart2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_2_LPCG, 16, 0, }, 64*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART2_BAUD_CLK, "uart2_lpcg_baud_clk", "uart2_clk", 0, ADMA_LPUART_2_LPCG, 0, 0, }, 65*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART3_IPG_CLK, "uart3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_3_LPCG, 16, 0, }, 66*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_UART3_BAUD_CLK, "uart3_lpcg_baud_clk", "uart3_clk", 0, ADMA_LPUART_3_LPCG, 0, 0, }, 67*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C0_IPG_CLK, "i2c0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_0_LPCG, 16, 0, }, 68*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C0_CLK, "i2c0_lpcg_clk", "i2c0_clk", 0, ADMA_LPI2C_0_LPCG, 0, 0, }, 69*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C1_IPG_CLK, "i2c1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_1_LPCG, 16, 0, }, 70*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C1_CLK, "i2c1_lpcg_clk", "i2c1_clk", 0, ADMA_LPI2C_1_LPCG, 0, 0, }, 71*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C2_IPG_CLK, "i2c2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_2_LPCG, 16, 0, }, 72*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, }, 73*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, }, 74*1e3121bfSAisheng Dong { IMX8QXP_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, }, 75*1e3121bfSAisheng Dong }; 76*1e3121bfSAisheng Dong 77*1e3121bfSAisheng Dong static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = { 78*1e3121bfSAisheng Dong .lpcg = imx8qxp_lpcg_adma, 79*1e3121bfSAisheng Dong .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_adma), 80*1e3121bfSAisheng Dong .num_max = IMX8QXP_ADMA_LPCG_CLK_END, 81*1e3121bfSAisheng Dong }; 82*1e3121bfSAisheng Dong 83*1e3121bfSAisheng Dong static const struct imx8qxp_lpcg_data imx8qxp_lpcg_conn[] = { 84*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC0_PER_CLK, "sdhc0_lpcg_per_clk", "sdhc0_clk", 0, CONN_USDHC_0_LPCG, 0, 0, }, 85*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC0_IPG_CLK, "sdhc0_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_0_LPCG, 16, 0, }, 86*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC0_HCLK, "sdhc0_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_0_LPCG, 20, 0, }, 87*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC1_PER_CLK, "sdhc1_lpcg_per_clk", "sdhc1_clk", 0, CONN_USDHC_1_LPCG, 0, 0, }, 88*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC1_IPG_CLK, "sdhc1_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_1_LPCG, 16, 0, }, 89*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC1_HCLK, "sdhc1_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_1_LPCG, 20, 0, }, 90*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC2_PER_CLK, "sdhc2_lpcg_per_clk", "sdhc2_clk", 0, CONN_USDHC_2_LPCG, 0, 0, }, 91*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC2_IPG_CLK, "sdhc2_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_2_LPCG, 16, 0, }, 92*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_SDHC2_HCLK, "sdhc2_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_2_LPCG, 20, 0, }, 93*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET0_ROOT_CLK, "enet0_ipg_root_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 0, 0, }, 94*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET0_TX_CLK, "enet0_tx_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 4, 0, }, 95*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET0_AHB_CLK, "enet0_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_0_LPCG, 8, 0, }, 96*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET0_IPG_S_CLK, "enet0_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_0_LPCG, 20, 0, }, 97*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET0_IPG_CLK, "enet0_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_0_LPCG, 16, 0, }, 98*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET1_ROOT_CLK, "enet1_ipg_root_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 0, 0, }, 99*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET1_TX_CLK, "enet1_tx_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 4, 0, }, 100*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET1_AHB_CLK, "enet1_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_1_LPCG, 8, 0, }, 101*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET1_IPG_S_CLK, "enet1_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_1_LPCG, 20, 0, }, 102*1e3121bfSAisheng Dong { IMX8QXP_CONN_LPCG_ENET1_IPG_CLK, "enet1_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_1_LPCG, 16, 0, }, 103*1e3121bfSAisheng Dong }; 104*1e3121bfSAisheng Dong 105*1e3121bfSAisheng Dong static const struct imx8qxp_ss_lpcg imx8qxp_ss_conn = { 106*1e3121bfSAisheng Dong .lpcg = imx8qxp_lpcg_conn, 107*1e3121bfSAisheng Dong .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_conn), 108*1e3121bfSAisheng Dong .num_max = IMX8QXP_CONN_LPCG_CLK_END, 109*1e3121bfSAisheng Dong }; 110*1e3121bfSAisheng Dong 111*1e3121bfSAisheng Dong static const struct imx8qxp_lpcg_data imx8qxp_lpcg_lsio[] = { 112*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM0_IPG_CLK, "pwm0_lpcg_ipg_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 0, 0, }, 113*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM0_IPG_HF_CLK, "pwm0_lpcg_ipg_hf_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 4, 0, }, 114*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM0_IPG_S_CLK, "pwm0_lpcg_ipg_s_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 16, 0, }, 115*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM0_IPG_SLV_CLK, "pwm0_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_0_LPCG, 20, 0, }, 116*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM0_IPG_MSTR_CLK, "pwm0_lpcg_ipg_mstr_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 24, 0, }, 117*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM1_IPG_CLK, "pwm1_lpcg_ipg_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 0, 0, }, 118*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM1_IPG_HF_CLK, "pwm1_lpcg_ipg_hf_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 4, 0, }, 119*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM1_IPG_S_CLK, "pwm1_lpcg_ipg_s_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 16, 0, }, 120*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM1_IPG_SLV_CLK, "pwm1_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_1_LPCG, 20, 0, }, 121*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM1_IPG_MSTR_CLK, "pwm1_lpcg_ipg_mstr_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 24, 0, }, 122*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM2_IPG_CLK, "pwm2_lpcg_ipg_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 0, 0, }, 123*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM2_IPG_HF_CLK, "pwm2_lpcg_ipg_hf_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 4, 0, }, 124*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM2_IPG_S_CLK, "pwm2_lpcg_ipg_s_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 16, 0, }, 125*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM2_IPG_SLV_CLK, "pwm2_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_2_LPCG, 20, 0, }, 126*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM2_IPG_MSTR_CLK, "pwm2_lpcg_ipg_mstr_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 24, 0, }, 127*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM3_IPG_CLK, "pwm3_lpcg_ipg_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 0, 0, }, 128*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM3_IPG_HF_CLK, "pwm3_lpcg_ipg_hf_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 4, 0, }, 129*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM3_IPG_S_CLK, "pwm3_lpcg_ipg_s_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 16, 0, }, 130*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM3_IPG_SLV_CLK, "pwm3_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_3_LPCG, 20, 0, }, 131*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM3_IPG_MSTR_CLK, "pwm3_lpcg_ipg_mstr_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 24, 0, }, 132*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM4_IPG_CLK, "pwm4_lpcg_ipg_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 0, 0, }, 133*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM4_IPG_HF_CLK, "pwm4_lpcg_ipg_hf_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 4, 0, }, 134*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM4_IPG_S_CLK, "pwm4_lpcg_ipg_s_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 16, 0, }, 135*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM4_IPG_SLV_CLK, "pwm4_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_4_LPCG, 20, 0, }, 136*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM4_IPG_MSTR_CLK, "pwm4_lpcg_ipg_mstr_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 24, 0, }, 137*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM5_IPG_CLK, "pwm5_lpcg_ipg_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 0, 0, }, 138*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM5_IPG_HF_CLK, "pwm5_lpcg_ipg_hf_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 4, 0, }, 139*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM5_IPG_S_CLK, "pwm5_lpcg_ipg_s_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 16, 0, }, 140*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM5_IPG_SLV_CLK, "pwm5_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_5_LPCG, 20, 0, }, 141*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM5_IPG_MSTR_CLK, "pwm5_lpcg_ipg_mstr_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 24, 0, }, 142*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM6_IPG_CLK, "pwm6_lpcg_ipg_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 0, 0, }, 143*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM6_IPG_HF_CLK, "pwm6_lpcg_ipg_hf_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 4, 0, }, 144*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM6_IPG_S_CLK, "pwm6_lpcg_ipg_s_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 16, 0, }, 145*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM6_IPG_SLV_CLK, "pwm6_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_6_LPCG, 20, 0, }, 146*1e3121bfSAisheng Dong { IMX8QXP_LSIO_LPCG_PWM6_IPG_MSTR_CLK, "pwm6_lpcg_ipg_mstr_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 24, 0, }, 147*1e3121bfSAisheng Dong }; 148*1e3121bfSAisheng Dong 149*1e3121bfSAisheng Dong static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = { 150*1e3121bfSAisheng Dong .lpcg = imx8qxp_lpcg_lsio, 151*1e3121bfSAisheng Dong .num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_lsio), 152*1e3121bfSAisheng Dong .num_max = IMX8QXP_LSIO_LPCG_CLK_END, 153*1e3121bfSAisheng Dong }; 154*1e3121bfSAisheng Dong 155*1e3121bfSAisheng Dong static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) 156*1e3121bfSAisheng Dong { 157*1e3121bfSAisheng Dong struct device *dev = &pdev->dev; 158*1e3121bfSAisheng Dong struct device_node *np = dev->of_node; 159*1e3121bfSAisheng Dong struct clk_hw_onecell_data *clk_data; 160*1e3121bfSAisheng Dong const struct imx8qxp_ss_lpcg *ss_lpcg; 161*1e3121bfSAisheng Dong const struct imx8qxp_lpcg_data *lpcg; 162*1e3121bfSAisheng Dong struct resource *res; 163*1e3121bfSAisheng Dong struct clk_hw **clks; 164*1e3121bfSAisheng Dong void __iomem *base; 165*1e3121bfSAisheng Dong int i; 166*1e3121bfSAisheng Dong 167*1e3121bfSAisheng Dong ss_lpcg = of_device_get_match_data(dev); 168*1e3121bfSAisheng Dong if (!ss_lpcg) 169*1e3121bfSAisheng Dong return -ENODEV; 170*1e3121bfSAisheng Dong 171*1e3121bfSAisheng Dong res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 172*1e3121bfSAisheng Dong base = devm_ioremap(dev, res->start, resource_size(res)); 173*1e3121bfSAisheng Dong if (!base) 174*1e3121bfSAisheng Dong return -ENOMEM; 175*1e3121bfSAisheng Dong 176*1e3121bfSAisheng Dong clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, 177*1e3121bfSAisheng Dong ss_lpcg->num_max), GFP_KERNEL); 178*1e3121bfSAisheng Dong if (!clk_data) 179*1e3121bfSAisheng Dong return -ENOMEM; 180*1e3121bfSAisheng Dong 181*1e3121bfSAisheng Dong clk_data->num = ss_lpcg->num_max; 182*1e3121bfSAisheng Dong clks = clk_data->hws; 183*1e3121bfSAisheng Dong 184*1e3121bfSAisheng Dong for (i = 0; i < ss_lpcg->num_lpcg; i++) { 185*1e3121bfSAisheng Dong lpcg = ss_lpcg->lpcg + i; 186*1e3121bfSAisheng Dong clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name, lpcg->parent, 187*1e3121bfSAisheng Dong lpcg->flags, base + lpcg->offset, 188*1e3121bfSAisheng Dong lpcg->bit_idx, lpcg->hw_gate); 189*1e3121bfSAisheng Dong } 190*1e3121bfSAisheng Dong 191*1e3121bfSAisheng Dong for (i = 0; i < clk_data->num; i++) { 192*1e3121bfSAisheng Dong if (IS_ERR(clks[i])) 193*1e3121bfSAisheng Dong pr_warn("i.MX clk %u: register failed with %ld\n", 194*1e3121bfSAisheng Dong i, PTR_ERR(clks[i])); 195*1e3121bfSAisheng Dong } 196*1e3121bfSAisheng Dong 197*1e3121bfSAisheng Dong return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); 198*1e3121bfSAisheng Dong } 199*1e3121bfSAisheng Dong 200*1e3121bfSAisheng Dong static const struct of_device_id imx8qxp_lpcg_match[] = { 201*1e3121bfSAisheng Dong { .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, }, 202*1e3121bfSAisheng Dong { .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, }, 203*1e3121bfSAisheng Dong { .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, }, 204*1e3121bfSAisheng Dong { /* sentinel */ } 205*1e3121bfSAisheng Dong }; 206*1e3121bfSAisheng Dong 207*1e3121bfSAisheng Dong static struct platform_driver imx8qxp_lpcg_clk_driver = { 208*1e3121bfSAisheng Dong .driver = { 209*1e3121bfSAisheng Dong .name = "imx8qxp-lpcg-clk", 210*1e3121bfSAisheng Dong .of_match_table = imx8qxp_lpcg_match, 211*1e3121bfSAisheng Dong .suppress_bind_attrs = true, 212*1e3121bfSAisheng Dong }, 213*1e3121bfSAisheng Dong .probe = imx8qxp_lpcg_clk_probe, 214*1e3121bfSAisheng Dong }; 215*1e3121bfSAisheng Dong 216*1e3121bfSAisheng Dong builtin_platform_driver(imx8qxp_lpcg_clk_driver); 217