xref: /openbmc/linux/drivers/clk/imx/clk-imx8qxp-lpcg.c (revision 08972760d366b83a87d366b0079747f8c409163c)
11e3121bfSAisheng Dong // SPDX-License-Identifier: GPL-2.0+
21e3121bfSAisheng Dong /*
31e3121bfSAisheng Dong  * Copyright 2018 NXP
41e3121bfSAisheng Dong  *	Dong Aisheng <aisheng.dong@nxp.com>
51e3121bfSAisheng Dong  */
61e3121bfSAisheng Dong 
71e3121bfSAisheng Dong #include <linux/clk-provider.h>
81e3121bfSAisheng Dong #include <linux/err.h>
91e3121bfSAisheng Dong #include <linux/io.h>
101e3121bfSAisheng Dong #include <linux/module.h>
111e3121bfSAisheng Dong #include <linux/of.h>
121e3121bfSAisheng Dong #include <linux/of_device.h>
131e3121bfSAisheng Dong #include <linux/platform_device.h>
141e3121bfSAisheng Dong #include <linux/slab.h>
151e3121bfSAisheng Dong 
161e3121bfSAisheng Dong #include "clk-scu.h"
171e3121bfSAisheng Dong #include "clk-imx8qxp-lpcg.h"
181e3121bfSAisheng Dong 
19*08972760SAisheng Dong #include <dt-bindings/clock/imx8-clock.h>
201e3121bfSAisheng Dong 
211e3121bfSAisheng Dong /*
221e3121bfSAisheng Dong  * struct imx8qxp_lpcg_data - Description of one LPCG clock
231e3121bfSAisheng Dong  * @id: clock ID
241e3121bfSAisheng Dong  * @name: clock name
251e3121bfSAisheng Dong  * @parent: parent clock name
261e3121bfSAisheng Dong  * @flags: common clock flags
271e3121bfSAisheng Dong  * @offset: offset of this LPCG clock
281e3121bfSAisheng Dong  * @bit_idx: bit index of this LPCG clock
291e3121bfSAisheng Dong  * @hw_gate: whether supports HW autogate
301e3121bfSAisheng Dong  *
311e3121bfSAisheng Dong  * This structure describes one LPCG clock
321e3121bfSAisheng Dong  */
331e3121bfSAisheng Dong struct imx8qxp_lpcg_data {
341e3121bfSAisheng Dong 	int id;
351e3121bfSAisheng Dong 	char *name;
361e3121bfSAisheng Dong 	char *parent;
371e3121bfSAisheng Dong 	unsigned long flags;
381e3121bfSAisheng Dong 	u32 offset;
391e3121bfSAisheng Dong 	u8 bit_idx;
401e3121bfSAisheng Dong 	bool hw_gate;
411e3121bfSAisheng Dong };
421e3121bfSAisheng Dong 
431e3121bfSAisheng Dong /*
441e3121bfSAisheng Dong  * struct imx8qxp_ss_lpcg - Description of one subsystem LPCG clocks
451e3121bfSAisheng Dong  * @lpcg: LPCG clocks array of one subsystem
461e3121bfSAisheng Dong  * @num_lpcg: the number of LPCG clocks
471e3121bfSAisheng Dong  * @num_max: the maximum number of LPCG clocks
481e3121bfSAisheng Dong  *
491e3121bfSAisheng Dong  * This structure describes each subsystem LPCG clocks information
501e3121bfSAisheng Dong  * which then will be used to create respective LPCGs clocks
511e3121bfSAisheng Dong  */
521e3121bfSAisheng Dong struct imx8qxp_ss_lpcg {
531e3121bfSAisheng Dong 	const struct imx8qxp_lpcg_data *lpcg;
541e3121bfSAisheng Dong 	u8 num_lpcg;
551e3121bfSAisheng Dong 	u8 num_max;
561e3121bfSAisheng Dong };
571e3121bfSAisheng Dong 
581e3121bfSAisheng Dong static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = {
59*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, },
60*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, },
61*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, },
62*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, },
63*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART2_IPG_CLK, "uart2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_2_LPCG, 16, 0, },
64*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART2_BAUD_CLK, "uart2_lpcg_baud_clk", "uart2_clk", 0, ADMA_LPUART_2_LPCG, 0, 0, },
65*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART3_IPG_CLK, "uart3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_3_LPCG, 16, 0, },
66*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_UART3_BAUD_CLK, "uart3_lpcg_baud_clk", "uart3_clk", 0, ADMA_LPUART_3_LPCG, 0, 0, },
67*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C0_IPG_CLK, "i2c0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_0_LPCG, 16, 0, },
68*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C0_CLK, "i2c0_lpcg_clk", "i2c0_clk", 0, ADMA_LPI2C_0_LPCG, 0, 0, },
69*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C1_IPG_CLK, "i2c1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_1_LPCG, 16, 0, },
70*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C1_CLK, "i2c1_lpcg_clk", "i2c1_clk", 0, ADMA_LPI2C_1_LPCG, 0, 0, },
71*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C2_IPG_CLK, "i2c2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_2_LPCG, 16, 0, },
72*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, },
73*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, },
74*08972760SAisheng Dong 	{ IMX_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, },
751e3121bfSAisheng Dong };
761e3121bfSAisheng Dong 
771e3121bfSAisheng Dong static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = {
781e3121bfSAisheng Dong 	.lpcg = imx8qxp_lpcg_adma,
791e3121bfSAisheng Dong 	.num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_adma),
80*08972760SAisheng Dong 	.num_max = IMX_ADMA_LPCG_CLK_END,
811e3121bfSAisheng Dong };
821e3121bfSAisheng Dong 
831e3121bfSAisheng Dong static const struct imx8qxp_lpcg_data imx8qxp_lpcg_conn[] = {
84*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC0_PER_CLK, "sdhc0_lpcg_per_clk", "sdhc0_clk", 0, CONN_USDHC_0_LPCG, 0, 0, },
85*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC0_IPG_CLK, "sdhc0_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_0_LPCG, 16, 0, },
86*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC0_HCLK, "sdhc0_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_0_LPCG, 20, 0, },
87*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC1_PER_CLK, "sdhc1_lpcg_per_clk", "sdhc1_clk", 0, CONN_USDHC_1_LPCG, 0, 0, },
88*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC1_IPG_CLK, "sdhc1_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_1_LPCG, 16, 0, },
89*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC1_HCLK, "sdhc1_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_1_LPCG, 20, 0, },
90*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC2_PER_CLK, "sdhc2_lpcg_per_clk", "sdhc2_clk", 0, CONN_USDHC_2_LPCG, 0, 0, },
91*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC2_IPG_CLK, "sdhc2_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_2_LPCG, 16, 0, },
92*08972760SAisheng Dong 	{ IMX_CONN_LPCG_SDHC2_HCLK, "sdhc2_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_2_LPCG, 20, 0, },
93*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET0_ROOT_CLK, "enet0_ipg_root_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 0, 0, },
94*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET0_TX_CLK, "enet0_tx_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 4, 0, },
95*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET0_AHB_CLK, "enet0_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_0_LPCG, 8, 0, },
96*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET0_IPG_S_CLK, "enet0_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_0_LPCG, 20, 0, },
97*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET0_IPG_CLK, "enet0_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_0_LPCG, 16, 0, },
98*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET1_ROOT_CLK, "enet1_ipg_root_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 0, 0, },
99*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET1_TX_CLK, "enet1_tx_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 4, 0, },
100*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET1_AHB_CLK, "enet1_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_1_LPCG, 8, 0, },
101*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET1_IPG_S_CLK, "enet1_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_1_LPCG, 20, 0, },
102*08972760SAisheng Dong 	{ IMX_CONN_LPCG_ENET1_IPG_CLK, "enet1_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_1_LPCG, 16, 0, },
1031e3121bfSAisheng Dong };
1041e3121bfSAisheng Dong 
1051e3121bfSAisheng Dong static const struct imx8qxp_ss_lpcg imx8qxp_ss_conn = {
1061e3121bfSAisheng Dong 	.lpcg = imx8qxp_lpcg_conn,
1071e3121bfSAisheng Dong 	.num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_conn),
108*08972760SAisheng Dong 	.num_max = IMX_CONN_LPCG_CLK_END,
1091e3121bfSAisheng Dong };
1101e3121bfSAisheng Dong 
1111e3121bfSAisheng Dong static const struct imx8qxp_lpcg_data imx8qxp_lpcg_lsio[] = {
112*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM0_IPG_CLK, "pwm0_lpcg_ipg_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 0, 0, },
113*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM0_IPG_HF_CLK, "pwm0_lpcg_ipg_hf_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 4, 0, },
114*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM0_IPG_S_CLK, "pwm0_lpcg_ipg_s_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 16, 0, },
115*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM0_IPG_SLV_CLK, "pwm0_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_0_LPCG, 20, 0, },
116*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM0_IPG_MSTR_CLK, "pwm0_lpcg_ipg_mstr_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 24, 0, },
117*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM1_IPG_CLK, "pwm1_lpcg_ipg_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 0, 0, },
118*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM1_IPG_HF_CLK, "pwm1_lpcg_ipg_hf_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 4, 0, },
119*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM1_IPG_S_CLK, "pwm1_lpcg_ipg_s_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 16, 0, },
120*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM1_IPG_SLV_CLK, "pwm1_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_1_LPCG, 20, 0, },
121*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM1_IPG_MSTR_CLK, "pwm1_lpcg_ipg_mstr_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 24, 0, },
122*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM2_IPG_CLK, "pwm2_lpcg_ipg_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 0, 0, },
123*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM2_IPG_HF_CLK, "pwm2_lpcg_ipg_hf_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 4, 0, },
124*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM2_IPG_S_CLK, "pwm2_lpcg_ipg_s_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 16, 0, },
125*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM2_IPG_SLV_CLK, "pwm2_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_2_LPCG, 20, 0, },
126*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM2_IPG_MSTR_CLK, "pwm2_lpcg_ipg_mstr_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 24, 0, },
127*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM3_IPG_CLK, "pwm3_lpcg_ipg_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 0, 0, },
128*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM3_IPG_HF_CLK, "pwm3_lpcg_ipg_hf_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 4, 0, },
129*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM3_IPG_S_CLK, "pwm3_lpcg_ipg_s_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 16, 0, },
130*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM3_IPG_SLV_CLK, "pwm3_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_3_LPCG, 20, 0, },
131*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM3_IPG_MSTR_CLK, "pwm3_lpcg_ipg_mstr_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 24, 0, },
132*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM4_IPG_CLK, "pwm4_lpcg_ipg_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 0, 0, },
133*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM4_IPG_HF_CLK, "pwm4_lpcg_ipg_hf_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 4, 0, },
134*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM4_IPG_S_CLK, "pwm4_lpcg_ipg_s_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 16, 0, },
135*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM4_IPG_SLV_CLK, "pwm4_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_4_LPCG, 20, 0, },
136*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM4_IPG_MSTR_CLK, "pwm4_lpcg_ipg_mstr_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 24, 0, },
137*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM5_IPG_CLK, "pwm5_lpcg_ipg_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 0, 0, },
138*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM5_IPG_HF_CLK, "pwm5_lpcg_ipg_hf_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 4, 0, },
139*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM5_IPG_S_CLK, "pwm5_lpcg_ipg_s_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 16, 0, },
140*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM5_IPG_SLV_CLK, "pwm5_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_5_LPCG, 20, 0, },
141*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM5_IPG_MSTR_CLK, "pwm5_lpcg_ipg_mstr_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 24, 0, },
142*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM6_IPG_CLK, "pwm6_lpcg_ipg_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 0, 0, },
143*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM6_IPG_HF_CLK, "pwm6_lpcg_ipg_hf_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 4, 0, },
144*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM6_IPG_S_CLK, "pwm6_lpcg_ipg_s_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 16, 0, },
145*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM6_IPG_SLV_CLK, "pwm6_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_6_LPCG, 20, 0, },
146*08972760SAisheng Dong 	{ IMX_LSIO_LPCG_PWM6_IPG_MSTR_CLK, "pwm6_lpcg_ipg_mstr_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 24, 0, },
1471e3121bfSAisheng Dong };
1481e3121bfSAisheng Dong 
1491e3121bfSAisheng Dong static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = {
1501e3121bfSAisheng Dong 	.lpcg = imx8qxp_lpcg_lsio,
1511e3121bfSAisheng Dong 	.num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_lsio),
152*08972760SAisheng Dong 	.num_max = IMX_LSIO_LPCG_CLK_END,
1531e3121bfSAisheng Dong };
1541e3121bfSAisheng Dong 
1551e3121bfSAisheng Dong static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
1561e3121bfSAisheng Dong {
1571e3121bfSAisheng Dong 	struct device *dev = &pdev->dev;
1581e3121bfSAisheng Dong 	struct device_node *np = dev->of_node;
1591e3121bfSAisheng Dong 	struct clk_hw_onecell_data *clk_data;
1601e3121bfSAisheng Dong 	const struct imx8qxp_ss_lpcg *ss_lpcg;
1611e3121bfSAisheng Dong 	const struct imx8qxp_lpcg_data *lpcg;
1621e3121bfSAisheng Dong 	struct resource *res;
1631e3121bfSAisheng Dong 	struct clk_hw **clks;
1641e3121bfSAisheng Dong 	void __iomem *base;
1651e3121bfSAisheng Dong 	int i;
1661e3121bfSAisheng Dong 
1671e3121bfSAisheng Dong 	ss_lpcg = of_device_get_match_data(dev);
1681e3121bfSAisheng Dong 	if (!ss_lpcg)
1691e3121bfSAisheng Dong 		return -ENODEV;
1701e3121bfSAisheng Dong 
1711e3121bfSAisheng Dong 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1721e3121bfSAisheng Dong 	base = devm_ioremap(dev, res->start, resource_size(res));
1731e3121bfSAisheng Dong 	if (!base)
1741e3121bfSAisheng Dong 		return -ENOMEM;
1751e3121bfSAisheng Dong 
1761e3121bfSAisheng Dong 	clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
1771e3121bfSAisheng Dong 				ss_lpcg->num_max), GFP_KERNEL);
1781e3121bfSAisheng Dong 	if (!clk_data)
1791e3121bfSAisheng Dong 		return -ENOMEM;
1801e3121bfSAisheng Dong 
1811e3121bfSAisheng Dong 	clk_data->num = ss_lpcg->num_max;
1821e3121bfSAisheng Dong 	clks = clk_data->hws;
1831e3121bfSAisheng Dong 
1841e3121bfSAisheng Dong 	for (i = 0; i < ss_lpcg->num_lpcg; i++) {
1851e3121bfSAisheng Dong 		lpcg = ss_lpcg->lpcg + i;
1861e3121bfSAisheng Dong 		clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name, lpcg->parent,
1871e3121bfSAisheng Dong 						  lpcg->flags, base + lpcg->offset,
1881e3121bfSAisheng Dong 						  lpcg->bit_idx, lpcg->hw_gate);
1891e3121bfSAisheng Dong 	}
1901e3121bfSAisheng Dong 
1911e3121bfSAisheng Dong 	for (i = 0; i < clk_data->num; i++) {
1921e3121bfSAisheng Dong 		if (IS_ERR(clks[i]))
1931e3121bfSAisheng Dong 			pr_warn("i.MX clk %u: register failed with %ld\n",
1941e3121bfSAisheng Dong 				i, PTR_ERR(clks[i]));
1951e3121bfSAisheng Dong 	}
1961e3121bfSAisheng Dong 
1971e3121bfSAisheng Dong 	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
1981e3121bfSAisheng Dong }
1991e3121bfSAisheng Dong 
2001e3121bfSAisheng Dong static const struct of_device_id imx8qxp_lpcg_match[] = {
2011e3121bfSAisheng Dong 	{ .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
2021e3121bfSAisheng Dong 	{ .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
2031e3121bfSAisheng Dong 	{ .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
2041e3121bfSAisheng Dong 	{ /* sentinel */ }
2051e3121bfSAisheng Dong };
2061e3121bfSAisheng Dong 
2071e3121bfSAisheng Dong static struct platform_driver imx8qxp_lpcg_clk_driver = {
2081e3121bfSAisheng Dong 	.driver = {
2091e3121bfSAisheng Dong 		.name = "imx8qxp-lpcg-clk",
2101e3121bfSAisheng Dong 		.of_match_table = imx8qxp_lpcg_match,
2111e3121bfSAisheng Dong 		.suppress_bind_attrs = true,
2121e3121bfSAisheng Dong 	},
2131e3121bfSAisheng Dong 	.probe = imx8qxp_lpcg_clk_probe,
2141e3121bfSAisheng Dong };
2151e3121bfSAisheng Dong 
2161e3121bfSAisheng Dong builtin_platform_driver(imx8qxp_lpcg_clk_driver);
217