xref: /linux/drivers/pmdomain/imx/imx93-pd.c (revision e2ad626f8f409899baf1bf192d0533a851128b19)
1*e2ad626fSUlf Hansson // SPDX-License-Identifier: GPL-2.0
2*e2ad626fSUlf Hansson /*
3*e2ad626fSUlf Hansson  * Copyright 2022 NXP
4*e2ad626fSUlf Hansson  */
5*e2ad626fSUlf Hansson 
6*e2ad626fSUlf Hansson #include <linux/clk.h>
7*e2ad626fSUlf Hansson #include <linux/delay.h>
8*e2ad626fSUlf Hansson #include <linux/iopoll.h>
9*e2ad626fSUlf Hansson #include <linux/mod_devicetable.h>
10*e2ad626fSUlf Hansson #include <linux/module.h>
11*e2ad626fSUlf Hansson #include <linux/platform_device.h>
12*e2ad626fSUlf Hansson #include <linux/pm_domain.h>
13*e2ad626fSUlf Hansson 
14*e2ad626fSUlf Hansson #define MIX_SLICE_SW_CTRL_OFF		0x20
15*e2ad626fSUlf Hansson #define SLICE_SW_CTRL_PSW_CTRL_OFF_MASK	BIT(4)
16*e2ad626fSUlf Hansson #define SLICE_SW_CTRL_PDN_SOFT_MASK	BIT(31)
17*e2ad626fSUlf Hansson 
18*e2ad626fSUlf Hansson #define MIX_FUNC_STAT_OFF		0xB4
19*e2ad626fSUlf Hansson 
20*e2ad626fSUlf Hansson #define FUNC_STAT_PSW_STAT_MASK		BIT(0)
21*e2ad626fSUlf Hansson #define FUNC_STAT_RST_STAT_MASK		BIT(2)
22*e2ad626fSUlf Hansson #define FUNC_STAT_ISO_STAT_MASK		BIT(4)
23*e2ad626fSUlf Hansson 
24*e2ad626fSUlf Hansson struct imx93_power_domain {
25*e2ad626fSUlf Hansson 	struct generic_pm_domain genpd;
26*e2ad626fSUlf Hansson 	struct device *dev;
27*e2ad626fSUlf Hansson 	void __iomem *addr;
28*e2ad626fSUlf Hansson 	struct clk_bulk_data *clks;
29*e2ad626fSUlf Hansson 	int num_clks;
30*e2ad626fSUlf Hansson 	bool init_off;
31*e2ad626fSUlf Hansson };
32*e2ad626fSUlf Hansson 
33*e2ad626fSUlf Hansson #define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd)
34*e2ad626fSUlf Hansson 
35*e2ad626fSUlf Hansson static int imx93_pd_on(struct generic_pm_domain *genpd)
36*e2ad626fSUlf Hansson {
37*e2ad626fSUlf Hansson 	struct imx93_power_domain *domain = to_imx93_pd(genpd);
38*e2ad626fSUlf Hansson 	void __iomem *addr = domain->addr;
39*e2ad626fSUlf Hansson 	u32 val;
40*e2ad626fSUlf Hansson 	int ret;
41*e2ad626fSUlf Hansson 
42*e2ad626fSUlf Hansson 	ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
43*e2ad626fSUlf Hansson 	if (ret) {
44*e2ad626fSUlf Hansson 		dev_err(domain->dev, "failed to enable clocks for domain: %s\n", genpd->name);
45*e2ad626fSUlf Hansson 		return ret;
46*e2ad626fSUlf Hansson 	}
47*e2ad626fSUlf Hansson 
48*e2ad626fSUlf Hansson 	val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
49*e2ad626fSUlf Hansson 	val &= ~SLICE_SW_CTRL_PDN_SOFT_MASK;
50*e2ad626fSUlf Hansson 	writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
51*e2ad626fSUlf Hansson 
52*e2ad626fSUlf Hansson 	ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
53*e2ad626fSUlf Hansson 				 !(val & FUNC_STAT_ISO_STAT_MASK), 1, 10000);
54*e2ad626fSUlf Hansson 	if (ret) {
55*e2ad626fSUlf Hansson 		dev_err(domain->dev, "pd_on timeout: name: %s, stat: %x\n", genpd->name, val);
56*e2ad626fSUlf Hansson 		return ret;
57*e2ad626fSUlf Hansson 	}
58*e2ad626fSUlf Hansson 
59*e2ad626fSUlf Hansson 	return 0;
60*e2ad626fSUlf Hansson }
61*e2ad626fSUlf Hansson 
62*e2ad626fSUlf Hansson static int imx93_pd_off(struct generic_pm_domain *genpd)
63*e2ad626fSUlf Hansson {
64*e2ad626fSUlf Hansson 	struct imx93_power_domain *domain = to_imx93_pd(genpd);
65*e2ad626fSUlf Hansson 	void __iomem *addr = domain->addr;
66*e2ad626fSUlf Hansson 	int ret;
67*e2ad626fSUlf Hansson 	u32 val;
68*e2ad626fSUlf Hansson 
69*e2ad626fSUlf Hansson 	/* Power off MIX */
70*e2ad626fSUlf Hansson 	val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
71*e2ad626fSUlf Hansson 	val |= SLICE_SW_CTRL_PDN_SOFT_MASK;
72*e2ad626fSUlf Hansson 	writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
73*e2ad626fSUlf Hansson 
74*e2ad626fSUlf Hansson 	ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
75*e2ad626fSUlf Hansson 				 val & FUNC_STAT_PSW_STAT_MASK, 1, 1000);
76*e2ad626fSUlf Hansson 	if (ret) {
77*e2ad626fSUlf Hansson 		dev_err(domain->dev, "pd_off timeout: name: %s, stat: %x\n", genpd->name, val);
78*e2ad626fSUlf Hansson 		return ret;
79*e2ad626fSUlf Hansson 	}
80*e2ad626fSUlf Hansson 
81*e2ad626fSUlf Hansson 	clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
82*e2ad626fSUlf Hansson 
83*e2ad626fSUlf Hansson 	return 0;
84*e2ad626fSUlf Hansson };
85*e2ad626fSUlf Hansson 
86*e2ad626fSUlf Hansson static int imx93_pd_remove(struct platform_device *pdev)
87*e2ad626fSUlf Hansson {
88*e2ad626fSUlf Hansson 	struct imx93_power_domain *domain = platform_get_drvdata(pdev);
89*e2ad626fSUlf Hansson 	struct device *dev = &pdev->dev;
90*e2ad626fSUlf Hansson 	struct device_node *np = dev->of_node;
91*e2ad626fSUlf Hansson 
92*e2ad626fSUlf Hansson 	if (!domain->init_off)
93*e2ad626fSUlf Hansson 		clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
94*e2ad626fSUlf Hansson 
95*e2ad626fSUlf Hansson 	of_genpd_del_provider(np);
96*e2ad626fSUlf Hansson 	pm_genpd_remove(&domain->genpd);
97*e2ad626fSUlf Hansson 
98*e2ad626fSUlf Hansson 	return 0;
99*e2ad626fSUlf Hansson }
100*e2ad626fSUlf Hansson 
101*e2ad626fSUlf Hansson static int imx93_pd_probe(struct platform_device *pdev)
102*e2ad626fSUlf Hansson {
103*e2ad626fSUlf Hansson 	struct device *dev = &pdev->dev;
104*e2ad626fSUlf Hansson 	struct device_node *np = dev->of_node;
105*e2ad626fSUlf Hansson 	struct imx93_power_domain *domain;
106*e2ad626fSUlf Hansson 	int ret;
107*e2ad626fSUlf Hansson 
108*e2ad626fSUlf Hansson 	domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
109*e2ad626fSUlf Hansson 	if (!domain)
110*e2ad626fSUlf Hansson 		return -ENOMEM;
111*e2ad626fSUlf Hansson 
112*e2ad626fSUlf Hansson 	domain->addr = devm_platform_ioremap_resource(pdev, 0);
113*e2ad626fSUlf Hansson 	if (IS_ERR(domain->addr))
114*e2ad626fSUlf Hansson 		return PTR_ERR(domain->addr);
115*e2ad626fSUlf Hansson 
116*e2ad626fSUlf Hansson 	domain->num_clks = devm_clk_bulk_get_all(dev, &domain->clks);
117*e2ad626fSUlf Hansson 	if (domain->num_clks < 0)
118*e2ad626fSUlf Hansson 		return dev_err_probe(dev, domain->num_clks, "Failed to get domain's clocks\n");
119*e2ad626fSUlf Hansson 
120*e2ad626fSUlf Hansson 	domain->genpd.name = dev_name(dev);
121*e2ad626fSUlf Hansson 	domain->genpd.power_off = imx93_pd_off;
122*e2ad626fSUlf Hansson 	domain->genpd.power_on = imx93_pd_on;
123*e2ad626fSUlf Hansson 	domain->dev = dev;
124*e2ad626fSUlf Hansson 
125*e2ad626fSUlf Hansson 	domain->init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK;
126*e2ad626fSUlf Hansson 	/* Just to sync the status of hardware */
127*e2ad626fSUlf Hansson 	if (!domain->init_off) {
128*e2ad626fSUlf Hansson 		ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
129*e2ad626fSUlf Hansson 		if (ret) {
130*e2ad626fSUlf Hansson 			dev_err(domain->dev, "failed to enable clocks for domain: %s\n",
131*e2ad626fSUlf Hansson 				domain->genpd.name);
132*e2ad626fSUlf Hansson 			return ret;
133*e2ad626fSUlf Hansson 		}
134*e2ad626fSUlf Hansson 	}
135*e2ad626fSUlf Hansson 
136*e2ad626fSUlf Hansson 	ret = pm_genpd_init(&domain->genpd, NULL, domain->init_off);
137*e2ad626fSUlf Hansson 	if (ret)
138*e2ad626fSUlf Hansson 		goto err_clk_unprepare;
139*e2ad626fSUlf Hansson 
140*e2ad626fSUlf Hansson 	platform_set_drvdata(pdev, domain);
141*e2ad626fSUlf Hansson 
142*e2ad626fSUlf Hansson 	ret = of_genpd_add_provider_simple(np, &domain->genpd);
143*e2ad626fSUlf Hansson 	if (ret)
144*e2ad626fSUlf Hansson 		goto err_genpd_remove;
145*e2ad626fSUlf Hansson 
146*e2ad626fSUlf Hansson 	return 0;
147*e2ad626fSUlf Hansson 
148*e2ad626fSUlf Hansson err_genpd_remove:
149*e2ad626fSUlf Hansson 	pm_genpd_remove(&domain->genpd);
150*e2ad626fSUlf Hansson 
151*e2ad626fSUlf Hansson err_clk_unprepare:
152*e2ad626fSUlf Hansson 	if (!domain->init_off)
153*e2ad626fSUlf Hansson 		clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
154*e2ad626fSUlf Hansson 
155*e2ad626fSUlf Hansson 	return ret;
156*e2ad626fSUlf Hansson }
157*e2ad626fSUlf Hansson 
158*e2ad626fSUlf Hansson static const struct of_device_id imx93_pd_ids[] = {
159*e2ad626fSUlf Hansson 	{ .compatible = "fsl,imx93-src-slice" },
160*e2ad626fSUlf Hansson 	{ }
161*e2ad626fSUlf Hansson };
162*e2ad626fSUlf Hansson MODULE_DEVICE_TABLE(of, imx93_pd_ids);
163*e2ad626fSUlf Hansson 
164*e2ad626fSUlf Hansson static struct platform_driver imx93_power_domain_driver = {
165*e2ad626fSUlf Hansson 	.driver = {
166*e2ad626fSUlf Hansson 		.name	= "imx93_power_domain",
167*e2ad626fSUlf Hansson 		.of_match_table = imx93_pd_ids,
168*e2ad626fSUlf Hansson 	},
169*e2ad626fSUlf Hansson 	.probe = imx93_pd_probe,
170*e2ad626fSUlf Hansson 	.remove = imx93_pd_remove,
171*e2ad626fSUlf Hansson };
172*e2ad626fSUlf Hansson module_platform_driver(imx93_power_domain_driver);
173*e2ad626fSUlf Hansson 
174*e2ad626fSUlf Hansson MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
175*e2ad626fSUlf Hansson MODULE_DESCRIPTION("NXP i.MX93 power domain driver");
176*e2ad626fSUlf Hansson MODULE_LICENSE("GPL");
177