162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright 2023 NXP
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <dt-bindings/clock/imx8-clock.h>
762306a36Sopenharmony_ci#include <linux/clk-provider.h>
862306a36Sopenharmony_ci#include <linux/device.h>
962306a36Sopenharmony_ci#include <linux/err.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/of_device.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/pm_domain.h>
1662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "clk.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/**
2262306a36Sopenharmony_ci * struct clk_imx_acm_pm_domains - structure for multi power domain
2362306a36Sopenharmony_ci * @pd_dev: power domain device
2462306a36Sopenharmony_ci * @pd_dev_link: power domain device link
2562306a36Sopenharmony_ci * @num_domains: power domain nummber
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cistruct clk_imx_acm_pm_domains {
2862306a36Sopenharmony_ci	struct device **pd_dev;
2962306a36Sopenharmony_ci	struct device_link **pd_dev_link;
3062306a36Sopenharmony_ci	int    num_domains;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/**
3462306a36Sopenharmony_ci * struct clk_imx8_acm_sel - for clock mux
3562306a36Sopenharmony_ci * @name: clock name
3662306a36Sopenharmony_ci * @clkid: clock id
3762306a36Sopenharmony_ci * @parents: clock parents
3862306a36Sopenharmony_ci * @num_parents: clock parents number
3962306a36Sopenharmony_ci * @reg: register offset
4062306a36Sopenharmony_ci * @shift: bit shift in register
4162306a36Sopenharmony_ci * @width: bits width
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_cistruct clk_imx8_acm_sel {
4462306a36Sopenharmony_ci	const char			*name;
4562306a36Sopenharmony_ci	int				clkid;
4662306a36Sopenharmony_ci	const struct clk_parent_data	*parents;	/* For mux */
4762306a36Sopenharmony_ci	int				num_parents;
4862306a36Sopenharmony_ci	u32				reg;
4962306a36Sopenharmony_ci	u8				shift;
5062306a36Sopenharmony_ci	u8				width;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/**
5462306a36Sopenharmony_ci * struct imx8_acm_soc_data - soc specific data
5562306a36Sopenharmony_ci * @sels: pointer to struct clk_imx8_acm_sel
5662306a36Sopenharmony_ci * @num_sels: numbers of items
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_cistruct imx8_acm_soc_data {
5962306a36Sopenharmony_ci	struct clk_imx8_acm_sel *sels;
6062306a36Sopenharmony_ci	unsigned int num_sels;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/**
6462306a36Sopenharmony_ci * struct imx8_acm_priv - private structure
6562306a36Sopenharmony_ci * @dev_pm: multi power domain
6662306a36Sopenharmony_ci * @soc_data: pointer to soc data
6762306a36Sopenharmony_ci * @reg: base address of registers
6862306a36Sopenharmony_ci * @regs: save registers for suspend
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistruct imx8_acm_priv {
7162306a36Sopenharmony_ci	struct clk_imx_acm_pm_domains dev_pm;
7262306a36Sopenharmony_ci	const struct imx8_acm_soc_data *soc_data;
7362306a36Sopenharmony_ci	void __iomem *reg;
7462306a36Sopenharmony_ci	u32 regs[IMX_ADMA_ACM_CLK_END];
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const struct clk_parent_data imx8qm_aud_clk_sels[] = {
7862306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk0_lpcg_clk" },
7962306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk1_lpcg_clk" },
8062306a36Sopenharmony_ci	{ .fw_name = "mlb_clk" },
8162306a36Sopenharmony_ci	{ .fw_name = "hdmi_rx_mclk" },
8262306a36Sopenharmony_ci	{ .fw_name = "ext_aud_mclk0" },
8362306a36Sopenharmony_ci	{ .fw_name = "ext_aud_mclk1" },
8462306a36Sopenharmony_ci	{ .fw_name = "esai0_rx_clk" },
8562306a36Sopenharmony_ci	{ .fw_name = "esai0_rx_hf_clk" },
8662306a36Sopenharmony_ci	{ .fw_name = "esai0_tx_clk" },
8762306a36Sopenharmony_ci	{ .fw_name = "esai0_tx_hf_clk" },
8862306a36Sopenharmony_ci	{ .fw_name = "esai1_rx_clk" },
8962306a36Sopenharmony_ci	{ .fw_name = "esai1_rx_hf_clk" },
9062306a36Sopenharmony_ci	{ .fw_name = "esai1_tx_clk" },
9162306a36Sopenharmony_ci	{ .fw_name = "esai1_tx_hf_clk" },
9262306a36Sopenharmony_ci	{ .fw_name = "spdif0_rx" },
9362306a36Sopenharmony_ci	{ .fw_name = "spdif1_rx" },
9462306a36Sopenharmony_ci	{ .fw_name = "sai0_rx_bclk" },
9562306a36Sopenharmony_ci	{ .fw_name = "sai0_tx_bclk" },
9662306a36Sopenharmony_ci	{ .fw_name = "sai1_rx_bclk" },
9762306a36Sopenharmony_ci	{ .fw_name = "sai1_tx_bclk" },
9862306a36Sopenharmony_ci	{ .fw_name = "sai2_rx_bclk" },
9962306a36Sopenharmony_ci	{ .fw_name = "sai3_rx_bclk" },
10062306a36Sopenharmony_ci	{ .fw_name = "sai4_rx_bclk" },
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic const struct clk_parent_data imx8qm_mclk_out_sels[] = {
10462306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk0_lpcg_clk" },
10562306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk1_lpcg_clk" },
10662306a36Sopenharmony_ci	{ .fw_name = "mlb_clk" },
10762306a36Sopenharmony_ci	{ .fw_name = "hdmi_rx_mclk" },
10862306a36Sopenharmony_ci	{ .fw_name = "spdif0_rx" },
10962306a36Sopenharmony_ci	{ .fw_name = "spdif1_rx" },
11062306a36Sopenharmony_ci	{ .fw_name = "sai4_rx_bclk" },
11162306a36Sopenharmony_ci	{ .fw_name = "sai6_rx_bclk" },
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic const struct clk_parent_data imx8qm_mclk_sels[] = {
11562306a36Sopenharmony_ci	{ .fw_name = "aud_pll_div_clk0_lpcg_clk" },
11662306a36Sopenharmony_ci	{ .fw_name = "aud_pll_div_clk1_lpcg_clk" },
11762306a36Sopenharmony_ci	{ .fw_name = "acm_aud_clk0_sel" },
11862306a36Sopenharmony_ci	{ .fw_name = "acm_aud_clk1_sel" },
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = {
12262306a36Sopenharmony_ci	{ .fw_name = "sai4_rx_bclk" },
12362306a36Sopenharmony_ci	{ .fw_name = "sai5_tx_bclk" },
12462306a36Sopenharmony_ci	{ .index = -1 },
12562306a36Sopenharmony_ci	{ .fw_name = "mlb_clk" },
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic struct clk_imx8_acm_sel imx8qm_sels[] = {
13062306a36Sopenharmony_ci	{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8qm_aud_clk_sels, ARRAY_SIZE(imx8qm_aud_clk_sels), 0x000000, 0, 5 },
13162306a36Sopenharmony_ci	{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8qm_aud_clk_sels, ARRAY_SIZE(imx8qm_aud_clk_sels), 0x010000, 0, 5 },
13262306a36Sopenharmony_ci	{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8qm_mclk_out_sels, ARRAY_SIZE(imx8qm_mclk_out_sels), 0x020000, 0, 3 },
13362306a36Sopenharmony_ci	{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8qm_mclk_out_sels, ARRAY_SIZE(imx8qm_mclk_out_sels), 0x030000, 0, 3 },
13462306a36Sopenharmony_ci	{ "acm_asrc0_mclk_sel", IMX_ADMA_ACM_ASRC0_MUX_CLK_SEL, imx8qm_asrc_mux_clk_sels, ARRAY_SIZE(imx8qm_asrc_mux_clk_sels), 0x040000, 0, 2 },
13562306a36Sopenharmony_ci	{ "acm_esai0_mclk_sel", IMX_ADMA_ACM_ESAI0_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x060000, 0, 2 },
13662306a36Sopenharmony_ci	{ "acm_esai1_mclk_sel", IMX_ADMA_ACM_ESAI1_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x070000, 0, 2 },
13762306a36Sopenharmony_ci	{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x0E0000, 0, 2 },
13862306a36Sopenharmony_ci	{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x0F0000, 0, 2 },
13962306a36Sopenharmony_ci	{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x100000, 0, 2 },
14062306a36Sopenharmony_ci	{ "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x110000, 0, 2 },
14162306a36Sopenharmony_ci	{ "acm_sai4_mclk_sel", IMX_ADMA_ACM_SAI4_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x120000, 0, 2 },
14262306a36Sopenharmony_ci	{ "acm_sai5_mclk_sel", IMX_ADMA_ACM_SAI5_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x130000, 0, 2 },
14362306a36Sopenharmony_ci	{ "acm_sai6_mclk_sel", IMX_ADMA_ACM_SAI6_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x140000, 0, 2 },
14462306a36Sopenharmony_ci	{ "acm_sai7_mclk_sel", IMX_ADMA_ACM_SAI7_MCLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x150000, 0, 2 },
14562306a36Sopenharmony_ci	{ "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1A0000, 0, 2 },
14662306a36Sopenharmony_ci	{ "acm_spdif1_mclk_sel", IMX_ADMA_ACM_SPDIF1_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1B0000, 0, 2 },
14762306a36Sopenharmony_ci	{ "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8qm_mclk_sels, ARRAY_SIZE(imx8qm_mclk_sels), 0x1C0000, 0, 2 },
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic const struct clk_parent_data imx8qxp_aud_clk_sels[] = {
15162306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk0_lpcg_clk" },
15262306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk1_lpcg_clk" },
15362306a36Sopenharmony_ci	{ .fw_name = "ext_aud_mclk0" },
15462306a36Sopenharmony_ci	{ .fw_name = "ext_aud_mclk1" },
15562306a36Sopenharmony_ci	{ .fw_name = "esai0_rx_clk" },
15662306a36Sopenharmony_ci	{ .fw_name = "esai0_rx_hf_clk" },
15762306a36Sopenharmony_ci	{ .fw_name = "esai0_tx_clk" },
15862306a36Sopenharmony_ci	{ .fw_name = "esai0_tx_hf_clk" },
15962306a36Sopenharmony_ci	{ .fw_name = "spdif0_rx" },
16062306a36Sopenharmony_ci	{ .fw_name = "sai0_rx_bclk" },
16162306a36Sopenharmony_ci	{ .fw_name = "sai0_tx_bclk" },
16262306a36Sopenharmony_ci	{ .fw_name = "sai1_rx_bclk" },
16362306a36Sopenharmony_ci	{ .fw_name = "sai1_tx_bclk" },
16462306a36Sopenharmony_ci	{ .fw_name = "sai2_rx_bclk" },
16562306a36Sopenharmony_ci	{ .fw_name = "sai3_rx_bclk" },
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic const struct clk_parent_data imx8qxp_mclk_out_sels[] = {
16962306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk0_lpcg_clk" },
17062306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk1_lpcg_clk" },
17162306a36Sopenharmony_ci	{ .index = -1 },
17262306a36Sopenharmony_ci	{ .index = -1 },
17362306a36Sopenharmony_ci	{ .fw_name = "spdif0_rx" },
17462306a36Sopenharmony_ci	{ .index = -1 },
17562306a36Sopenharmony_ci	{ .index = -1 },
17662306a36Sopenharmony_ci	{ .fw_name = "sai4_rx_bclk" },
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic const struct clk_parent_data imx8qxp_mclk_sels[] = {
18062306a36Sopenharmony_ci	{ .fw_name = "aud_pll_div_clk0_lpcg_clk" },
18162306a36Sopenharmony_ci	{ .fw_name = "aud_pll_div_clk1_lpcg_clk" },
18262306a36Sopenharmony_ci	{ .fw_name = "acm_aud_clk0_sel" },
18362306a36Sopenharmony_ci	{ .fw_name = "acm_aud_clk1_sel" },
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic struct clk_imx8_acm_sel imx8qxp_sels[] = {
18762306a36Sopenharmony_ci	{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8qxp_aud_clk_sels, ARRAY_SIZE(imx8qxp_aud_clk_sels), 0x000000, 0, 5 },
18862306a36Sopenharmony_ci	{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8qxp_aud_clk_sels, ARRAY_SIZE(imx8qxp_aud_clk_sels), 0x010000, 0, 5 },
18962306a36Sopenharmony_ci	{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8qxp_mclk_out_sels, ARRAY_SIZE(imx8qxp_mclk_out_sels), 0x020000, 0, 3 },
19062306a36Sopenharmony_ci	{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8qxp_mclk_out_sels, ARRAY_SIZE(imx8qxp_mclk_out_sels), 0x030000, 0, 3 },
19162306a36Sopenharmony_ci	{ "acm_esai0_mclk_sel", IMX_ADMA_ACM_ESAI0_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x060000, 0, 2 },
19262306a36Sopenharmony_ci	{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x0E0000, 0, 2 },
19362306a36Sopenharmony_ci	{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x0F0000, 0, 2 },
19462306a36Sopenharmony_ci	{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x100000, 0, 2 },
19562306a36Sopenharmony_ci	{ "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x110000, 0, 2 },
19662306a36Sopenharmony_ci	{ "acm_sai4_mclk_sel", IMX_ADMA_ACM_SAI4_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x140000, 0, 2 },
19762306a36Sopenharmony_ci	{ "acm_sai5_mclk_sel", IMX_ADMA_ACM_SAI5_MCLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x150000, 0, 2 },
19862306a36Sopenharmony_ci	{ "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x1A0000, 0, 2 },
19962306a36Sopenharmony_ci	{ "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8qxp_mclk_sels, ARRAY_SIZE(imx8qxp_mclk_sels), 0x1C0000, 0, 2 },
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic const struct clk_parent_data imx8dxl_aud_clk_sels[] = {
20362306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk0_lpcg_clk" },
20462306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk1_lpcg_clk" },
20562306a36Sopenharmony_ci	{ .fw_name = "ext_aud_mclk0" },
20662306a36Sopenharmony_ci	{ .fw_name = "ext_aud_mclk1" },
20762306a36Sopenharmony_ci	{ .index = -1 },
20862306a36Sopenharmony_ci	{ .index = -1 },
20962306a36Sopenharmony_ci	{ .index = -1 },
21062306a36Sopenharmony_ci	{ .index = -1 },
21162306a36Sopenharmony_ci	{ .fw_name = "spdif0_rx" },
21262306a36Sopenharmony_ci	{ .fw_name = "sai0_rx_bclk" },
21362306a36Sopenharmony_ci	{ .fw_name = "sai0_tx_bclk" },
21462306a36Sopenharmony_ci	{ .fw_name = "sai1_rx_bclk" },
21562306a36Sopenharmony_ci	{ .fw_name = "sai1_tx_bclk" },
21662306a36Sopenharmony_ci	{ .fw_name = "sai2_rx_bclk" },
21762306a36Sopenharmony_ci	{ .fw_name = "sai3_rx_bclk" },
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic const struct clk_parent_data imx8dxl_mclk_out_sels[] = {
22162306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk0_lpcg_clk" },
22262306a36Sopenharmony_ci	{ .fw_name = "aud_rec_clk1_lpcg_clk" },
22362306a36Sopenharmony_ci	{ .index = -1 },
22462306a36Sopenharmony_ci	{ .index = -1 },
22562306a36Sopenharmony_ci	{ .fw_name = "spdif0_rx" },
22662306a36Sopenharmony_ci	{ .index = -1 },
22762306a36Sopenharmony_ci	{ .index = -1 },
22862306a36Sopenharmony_ci	{ .index = -1 },
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic const struct clk_parent_data imx8dxl_mclk_sels[] = {
23262306a36Sopenharmony_ci	{ .fw_name = "aud_pll_div_clk0_lpcg_clk" },
23362306a36Sopenharmony_ci	{ .fw_name = "aud_pll_div_clk1_lpcg_clk" },
23462306a36Sopenharmony_ci	{ .fw_name = "acm_aud_clk0_sel" },
23562306a36Sopenharmony_ci	{ .fw_name = "acm_aud_clk1_sel" },
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic struct clk_imx8_acm_sel imx8dxl_sels[] = {
23962306a36Sopenharmony_ci	{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x000000, 0, 5 },
24062306a36Sopenharmony_ci	{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x010000, 0, 5 },
24162306a36Sopenharmony_ci	{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x020000, 0, 3 },
24262306a36Sopenharmony_ci	{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x030000, 0, 3 },
24362306a36Sopenharmony_ci	{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0E0000, 0, 2 },
24462306a36Sopenharmony_ci	{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0F0000, 0, 2 },
24562306a36Sopenharmony_ci	{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x100000, 0, 2 },
24662306a36Sopenharmony_ci	{ "acm_sai3_mclk_sel", IMX_ADMA_ACM_SAI3_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x110000, 0, 2 },
24762306a36Sopenharmony_ci	{ "acm_spdif0_mclk_sel", IMX_ADMA_ACM_SPDIF0_TX_CLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x1A0000, 0, 2 },
24862306a36Sopenharmony_ci	{ "acm_mqs_mclk_sel", IMX_ADMA_ACM_MQS_TX_CLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x1C0000, 0, 2 },
24962306a36Sopenharmony_ci};
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/**
25262306a36Sopenharmony_ci * clk_imx_acm_attach_pm_domains: attach multi power domains
25362306a36Sopenharmony_ci * @dev: device pointer
25462306a36Sopenharmony_ci * @dev_pm: power domains for device
25562306a36Sopenharmony_ci */
25662306a36Sopenharmony_cistatic int clk_imx_acm_attach_pm_domains(struct device *dev,
25762306a36Sopenharmony_ci					 struct clk_imx_acm_pm_domains *dev_pm)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	int ret;
26062306a36Sopenharmony_ci	int i;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	dev_pm->num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
26362306a36Sopenharmony_ci							 "#power-domain-cells");
26462306a36Sopenharmony_ci	if (dev_pm->num_domains <= 1)
26562306a36Sopenharmony_ci		return 0;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	dev_pm->pd_dev = devm_kmalloc_array(dev, dev_pm->num_domains,
26862306a36Sopenharmony_ci					    sizeof(*dev_pm->pd_dev),
26962306a36Sopenharmony_ci					    GFP_KERNEL);
27062306a36Sopenharmony_ci	if (!dev_pm->pd_dev)
27162306a36Sopenharmony_ci		return -ENOMEM;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	dev_pm->pd_dev_link = devm_kmalloc_array(dev,
27462306a36Sopenharmony_ci						 dev_pm->num_domains,
27562306a36Sopenharmony_ci						 sizeof(*dev_pm->pd_dev_link),
27662306a36Sopenharmony_ci						 GFP_KERNEL);
27762306a36Sopenharmony_ci	if (!dev_pm->pd_dev_link)
27862306a36Sopenharmony_ci		return -ENOMEM;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	for (i = 0; i < dev_pm->num_domains; i++) {
28162306a36Sopenharmony_ci		dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
28262306a36Sopenharmony_ci		if (IS_ERR(dev_pm->pd_dev[i])) {
28362306a36Sopenharmony_ci			ret = PTR_ERR(dev_pm->pd_dev[i]);
28462306a36Sopenharmony_ci			goto detach_pm;
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		dev_pm->pd_dev_link[i] = device_link_add(dev,
28862306a36Sopenharmony_ci							 dev_pm->pd_dev[i],
28962306a36Sopenharmony_ci							 DL_FLAG_STATELESS |
29062306a36Sopenharmony_ci							 DL_FLAG_PM_RUNTIME |
29162306a36Sopenharmony_ci							 DL_FLAG_RPM_ACTIVE);
29262306a36Sopenharmony_ci		if (IS_ERR(dev_pm->pd_dev_link[i])) {
29362306a36Sopenharmony_ci			dev_pm_domain_detach(dev_pm->pd_dev[i], false);
29462306a36Sopenharmony_ci			ret = PTR_ERR(dev_pm->pd_dev_link[i]);
29562306a36Sopenharmony_ci			goto detach_pm;
29662306a36Sopenharmony_ci		}
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cidetach_pm:
30162306a36Sopenharmony_ci	while (--i >= 0) {
30262306a36Sopenharmony_ci		device_link_del(dev_pm->pd_dev_link[i]);
30362306a36Sopenharmony_ci		dev_pm_domain_detach(dev_pm->pd_dev[i], false);
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci	return ret;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/**
30962306a36Sopenharmony_ci * clk_imx_acm_detach_pm_domains: detach multi power domains
31062306a36Sopenharmony_ci * @dev: deivice pointer
31162306a36Sopenharmony_ci * @dev_pm: multi power domain for device
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_cistatic int clk_imx_acm_detach_pm_domains(struct device *dev,
31462306a36Sopenharmony_ci					 struct clk_imx_acm_pm_domains *dev_pm)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	int i;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (dev_pm->num_domains <= 1)
31962306a36Sopenharmony_ci		return 0;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	for (i = 0; i < dev_pm->num_domains; i++) {
32262306a36Sopenharmony_ci		device_link_del(dev_pm->pd_dev_link[i]);
32362306a36Sopenharmony_ci		dev_pm_domain_detach(dev_pm->pd_dev[i], false);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic int imx8_acm_clk_probe(struct platform_device *pdev)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct clk_hw_onecell_data *clk_hw_data;
33262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
33362306a36Sopenharmony_ci	struct clk_imx8_acm_sel *sels;
33462306a36Sopenharmony_ci	struct imx8_acm_priv *priv;
33562306a36Sopenharmony_ci	struct clk_hw **hws;
33662306a36Sopenharmony_ci	void __iomem *base;
33762306a36Sopenharmony_ci	int ret;
33862306a36Sopenharmony_ci	int i;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	base = devm_of_iomap(dev, dev->of_node, 0, NULL);
34162306a36Sopenharmony_ci	if (WARN_ON(IS_ERR(base)))
34262306a36Sopenharmony_ci		return PTR_ERR(base);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
34562306a36Sopenharmony_ci	if (!priv)
34662306a36Sopenharmony_ci		return -ENOMEM;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	priv->reg = base;
34962306a36Sopenharmony_ci	priv->soc_data = of_device_get_match_data(dev);
35062306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	clk_hw_data = devm_kzalloc(&pdev->dev, struct_size(clk_hw_data, hws, IMX_ADMA_ACM_CLK_END),
35362306a36Sopenharmony_ci				   GFP_KERNEL);
35462306a36Sopenharmony_ci	if (!clk_hw_data)
35562306a36Sopenharmony_ci		return -ENOMEM;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	clk_hw_data->num = IMX_ADMA_ACM_CLK_END;
35862306a36Sopenharmony_ci	hws = clk_hw_data->hws;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ret = clk_imx_acm_attach_pm_domains(&pdev->dev, &priv->dev_pm);
36162306a36Sopenharmony_ci	if (ret)
36262306a36Sopenharmony_ci		return ret;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
36562306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	sels = priv->soc_data->sels;
36862306a36Sopenharmony_ci	for (i = 0; i < priv->soc_data->num_sels; i++) {
36962306a36Sopenharmony_ci		hws[sels[i].clkid] = devm_clk_hw_register_mux_parent_data_table(dev,
37062306a36Sopenharmony_ci										sels[i].name, sels[i].parents,
37162306a36Sopenharmony_ci										sels[i].num_parents, 0,
37262306a36Sopenharmony_ci										base + sels[i].reg,
37362306a36Sopenharmony_ci										sels[i].shift, sels[i].width,
37462306a36Sopenharmony_ci										0, NULL, NULL);
37562306a36Sopenharmony_ci		if (IS_ERR(hws[sels[i].clkid])) {
37662306a36Sopenharmony_ci			ret = PTR_ERR(hws[sels[i].clkid]);
37762306a36Sopenharmony_ci			goto err_clk_register;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data);
38462306a36Sopenharmony_ci	if (ret < 0) {
38562306a36Sopenharmony_ci		dev_err(dev, "failed to register hws for ACM\n");
38662306a36Sopenharmony_ci		goto err_clk_register;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cierr_clk_register:
39362306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
39462306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
39562306a36Sopenharmony_ci	clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return ret;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic int imx8_acm_clk_remove(struct platform_device *pdev)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct imx8_acm_priv *priv = dev_get_drvdata(&pdev->dev);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return 0;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic const struct imx8_acm_soc_data imx8qm_acm_data = {
41262306a36Sopenharmony_ci	.sels = imx8qm_sels,
41362306a36Sopenharmony_ci	.num_sels = ARRAY_SIZE(imx8qm_sels),
41462306a36Sopenharmony_ci};
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic const struct imx8_acm_soc_data imx8qxp_acm_data = {
41762306a36Sopenharmony_ci	.sels = imx8qxp_sels,
41862306a36Sopenharmony_ci	.num_sels = ARRAY_SIZE(imx8qxp_sels),
41962306a36Sopenharmony_ci};
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic const struct imx8_acm_soc_data imx8dxl_acm_data = {
42262306a36Sopenharmony_ci	.sels = imx8dxl_sels,
42362306a36Sopenharmony_ci	.num_sels = ARRAY_SIZE(imx8dxl_sels),
42462306a36Sopenharmony_ci};
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic const struct of_device_id imx8_acm_match[] = {
42762306a36Sopenharmony_ci	{ .compatible = "fsl,imx8qm-acm", .data = &imx8qm_acm_data },
42862306a36Sopenharmony_ci	{ .compatible = "fsl,imx8qxp-acm", .data = &imx8qxp_acm_data },
42962306a36Sopenharmony_ci	{ .compatible = "fsl,imx8dxl-acm", .data = &imx8dxl_acm_data },
43062306a36Sopenharmony_ci	{ /* sentinel */ }
43162306a36Sopenharmony_ci};
43262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx8_acm_match);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic int __maybe_unused imx8_acm_runtime_suspend(struct device *dev)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct imx8_acm_priv *priv = dev_get_drvdata(dev);
43762306a36Sopenharmony_ci	struct clk_imx8_acm_sel *sels;
43862306a36Sopenharmony_ci	int i;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	sels = priv->soc_data->sels;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	for (i = 0; i < priv->soc_data->num_sels; i++)
44362306a36Sopenharmony_ci		priv->regs[i] = readl_relaxed(priv->reg + sels[i].reg);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int __maybe_unused imx8_acm_runtime_resume(struct device *dev)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	struct imx8_acm_priv *priv = dev_get_drvdata(dev);
45162306a36Sopenharmony_ci	struct clk_imx8_acm_sel *sels;
45262306a36Sopenharmony_ci	int i;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	sels = priv->soc_data->sels;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	for (i = 0; i < priv->soc_data->num_sels; i++)
45762306a36Sopenharmony_ci		writel_relaxed(priv->regs[i], priv->reg + sels[i].reg);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return 0;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic const struct dev_pm_ops imx8_acm_pm_ops = {
46362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(imx8_acm_runtime_suspend,
46462306a36Sopenharmony_ci			   imx8_acm_runtime_resume, NULL)
46562306a36Sopenharmony_ci	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
46662306a36Sopenharmony_ci				      pm_runtime_force_resume)
46762306a36Sopenharmony_ci};
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic struct platform_driver imx8_acm_clk_driver = {
47062306a36Sopenharmony_ci	.driver = {
47162306a36Sopenharmony_ci		.name = "imx8-acm",
47262306a36Sopenharmony_ci		.of_match_table = imx8_acm_match,
47362306a36Sopenharmony_ci		.pm = &imx8_acm_pm_ops,
47462306a36Sopenharmony_ci	},
47562306a36Sopenharmony_ci	.probe = imx8_acm_clk_probe,
47662306a36Sopenharmony_ci	.remove = imx8_acm_clk_remove,
47762306a36Sopenharmony_ci};
47862306a36Sopenharmony_cimodule_platform_driver(imx8_acm_clk_driver);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ciMODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
48162306a36Sopenharmony_ciMODULE_DESCRIPTION("Freescale i.MX8 Audio Clock Mux driver");
48262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
483