1*e2ad626fSUlf Hansson // SPDX-License-Identifier: GPL-2.0-only OR MIT
2*e2ad626fSUlf Hansson /*
3*e2ad626fSUlf Hansson  * Apple SoC PMGR device power state driver
4*e2ad626fSUlf Hansson  *
5*e2ad626fSUlf Hansson  * Copyright The Asahi Linux Contributors
6*e2ad626fSUlf Hansson  */
7*e2ad626fSUlf Hansson 
8*e2ad626fSUlf Hansson #include <linux/bitops.h>
9*e2ad626fSUlf Hansson #include <linux/bitfield.h>
10*e2ad626fSUlf Hansson #include <linux/err.h>
11*e2ad626fSUlf Hansson #include <linux/of.h>
12*e2ad626fSUlf Hansson #include <linux/of_address.h>
13*e2ad626fSUlf Hansson #include <linux/platform_device.h>
14*e2ad626fSUlf Hansson #include <linux/pm_domain.h>
15*e2ad626fSUlf Hansson #include <linux/regmap.h>
16*e2ad626fSUlf Hansson #include <linux/mfd/syscon.h>
17*e2ad626fSUlf Hansson #include <linux/reset-controller.h>
18*e2ad626fSUlf Hansson #include <linux/module.h>
19*e2ad626fSUlf Hansson 
20*e2ad626fSUlf Hansson #define APPLE_PMGR_RESET        BIT(31)
21*e2ad626fSUlf Hansson #define APPLE_PMGR_AUTO_ENABLE  BIT(28)
22*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_AUTO      GENMASK(27, 24)
23*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_MIN       GENMASK(19, 16)
24*e2ad626fSUlf Hansson #define APPLE_PMGR_PARENT_OFF   BIT(11)
25*e2ad626fSUlf Hansson #define APPLE_PMGR_DEV_DISABLE  BIT(10)
26*e2ad626fSUlf Hansson #define APPLE_PMGR_WAS_CLKGATED BIT(9)
27*e2ad626fSUlf Hansson #define APPLE_PMGR_WAS_PWRGATED BIT(8)
28*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_ACTUAL    GENMASK(7, 4)
29*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_TARGET    GENMASK(3, 0)
30*e2ad626fSUlf Hansson 
31*e2ad626fSUlf Hansson #define APPLE_PMGR_FLAGS        (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED)
32*e2ad626fSUlf Hansson 
33*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_ACTIVE    0xf
34*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_CLKGATE   0x4
35*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_PWRGATE   0x0
36*e2ad626fSUlf Hansson 
37*e2ad626fSUlf Hansson #define APPLE_PMGR_PS_SET_TIMEOUT 100
38*e2ad626fSUlf Hansson #define APPLE_PMGR_RESET_TIME 1
39*e2ad626fSUlf Hansson 
40*e2ad626fSUlf Hansson struct apple_pmgr_ps {
41*e2ad626fSUlf Hansson 	struct device *dev;
42*e2ad626fSUlf Hansson 	struct generic_pm_domain genpd;
43*e2ad626fSUlf Hansson 	struct reset_controller_dev rcdev;
44*e2ad626fSUlf Hansson 	struct regmap *regmap;
45*e2ad626fSUlf Hansson 	u32 offset;
46*e2ad626fSUlf Hansson 	u32 min_state;
47*e2ad626fSUlf Hansson };
48*e2ad626fSUlf Hansson 
49*e2ad626fSUlf Hansson #define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd)
50*e2ad626fSUlf Hansson #define rcdev_to_apple_pmgr_ps(_rcdev) container_of(_rcdev, struct apple_pmgr_ps, rcdev)
51*e2ad626fSUlf Hansson 
apple_pmgr_ps_set(struct generic_pm_domain * genpd,u32 pstate,bool auto_enable)52*e2ad626fSUlf Hansson static int apple_pmgr_ps_set(struct generic_pm_domain *genpd, u32 pstate, bool auto_enable)
53*e2ad626fSUlf Hansson {
54*e2ad626fSUlf Hansson 	int ret;
55*e2ad626fSUlf Hansson 	struct apple_pmgr_ps *ps = genpd_to_apple_pmgr_ps(genpd);
56*e2ad626fSUlf Hansson 	u32 reg;
57*e2ad626fSUlf Hansson 
58*e2ad626fSUlf Hansson 	ret = regmap_read(ps->regmap, ps->offset, &reg);
59*e2ad626fSUlf Hansson 	if (ret < 0)
60*e2ad626fSUlf Hansson 		return ret;
61*e2ad626fSUlf Hansson 
62*e2ad626fSUlf Hansson 	/* Resets are synchronous, and only work if the device is powered and clocked. */
63*e2ad626fSUlf Hansson 	if (reg & APPLE_PMGR_RESET && pstate != APPLE_PMGR_PS_ACTIVE)
64*e2ad626fSUlf Hansson 		dev_err(ps->dev, "PS %s: powering off with RESET active\n",
65*e2ad626fSUlf Hansson 			genpd->name);
66*e2ad626fSUlf Hansson 
67*e2ad626fSUlf Hansson 	reg &= ~(APPLE_PMGR_AUTO_ENABLE | APPLE_PMGR_FLAGS | APPLE_PMGR_PS_TARGET);
68*e2ad626fSUlf Hansson 	reg |= FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate);
69*e2ad626fSUlf Hansson 
70*e2ad626fSUlf Hansson 	dev_dbg(ps->dev, "PS %s: pwrstate = 0x%x: 0x%x\n", genpd->name, pstate, reg);
71*e2ad626fSUlf Hansson 
72*e2ad626fSUlf Hansson 	regmap_write(ps->regmap, ps->offset, reg);
73*e2ad626fSUlf Hansson 
74*e2ad626fSUlf Hansson 	ret = regmap_read_poll_timeout_atomic(
75*e2ad626fSUlf Hansson 		ps->regmap, ps->offset, reg,
76*e2ad626fSUlf Hansson 		(FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1,
77*e2ad626fSUlf Hansson 		APPLE_PMGR_PS_SET_TIMEOUT);
78*e2ad626fSUlf Hansson 	if (ret < 0)
79*e2ad626fSUlf Hansson 		dev_err(ps->dev, "PS %s: Failed to reach power state 0x%x (now: 0x%x)\n",
80*e2ad626fSUlf Hansson 			genpd->name, pstate, reg);
81*e2ad626fSUlf Hansson 
82*e2ad626fSUlf Hansson 	if (auto_enable) {
83*e2ad626fSUlf Hansson 		/* Not all devices implement this; this is a no-op where not implemented. */
84*e2ad626fSUlf Hansson 		reg &= ~APPLE_PMGR_FLAGS;
85*e2ad626fSUlf Hansson 		reg |= APPLE_PMGR_AUTO_ENABLE;
86*e2ad626fSUlf Hansson 		regmap_write(ps->regmap, ps->offset, reg);
87*e2ad626fSUlf Hansson 	}
88*e2ad626fSUlf Hansson 
89*e2ad626fSUlf Hansson 	return ret;
90*e2ad626fSUlf Hansson }
91*e2ad626fSUlf Hansson 
apple_pmgr_ps_is_active(struct apple_pmgr_ps * ps)92*e2ad626fSUlf Hansson static bool apple_pmgr_ps_is_active(struct apple_pmgr_ps *ps)
93*e2ad626fSUlf Hansson {
94*e2ad626fSUlf Hansson 	u32 reg = 0;
95*e2ad626fSUlf Hansson 
96*e2ad626fSUlf Hansson 	regmap_read(ps->regmap, ps->offset, &reg);
97*e2ad626fSUlf Hansson 	/*
98*e2ad626fSUlf Hansson 	 * We consider domains as active if they are actually on, or if they have auto-PM
99*e2ad626fSUlf Hansson 	 * enabled and the intended target is on.
100*e2ad626fSUlf Hansson 	 */
101*e2ad626fSUlf Hansson 	return (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == APPLE_PMGR_PS_ACTIVE ||
102*e2ad626fSUlf Hansson 		(FIELD_GET(APPLE_PMGR_PS_TARGET, reg) == APPLE_PMGR_PS_ACTIVE &&
103*e2ad626fSUlf Hansson 		 reg & APPLE_PMGR_AUTO_ENABLE));
104*e2ad626fSUlf Hansson }
105*e2ad626fSUlf Hansson 
apple_pmgr_ps_power_on(struct generic_pm_domain * genpd)106*e2ad626fSUlf Hansson static int apple_pmgr_ps_power_on(struct generic_pm_domain *genpd)
107*e2ad626fSUlf Hansson {
108*e2ad626fSUlf Hansson 	return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_ACTIVE, true);
109*e2ad626fSUlf Hansson }
110*e2ad626fSUlf Hansson 
apple_pmgr_ps_power_off(struct generic_pm_domain * genpd)111*e2ad626fSUlf Hansson static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd)
112*e2ad626fSUlf Hansson {
113*e2ad626fSUlf Hansson 	return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_PWRGATE, false);
114*e2ad626fSUlf Hansson }
115*e2ad626fSUlf Hansson 
apple_pmgr_reset_assert(struct reset_controller_dev * rcdev,unsigned long id)116*e2ad626fSUlf Hansson static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
117*e2ad626fSUlf Hansson {
118*e2ad626fSUlf Hansson 	struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
119*e2ad626fSUlf Hansson 	unsigned long flags;
120*e2ad626fSUlf Hansson 
121*e2ad626fSUlf Hansson 	spin_lock_irqsave(&ps->genpd.slock, flags);
122*e2ad626fSUlf Hansson 
123*e2ad626fSUlf Hansson 	if (ps->genpd.status == GENPD_STATE_OFF)
124*e2ad626fSUlf Hansson 		dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset);
125*e2ad626fSUlf Hansson 
126*e2ad626fSUlf Hansson 	dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset);
127*e2ad626fSUlf Hansson 	/* Quiesce device before asserting reset */
128*e2ad626fSUlf Hansson 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE,
129*e2ad626fSUlf Hansson 			   APPLE_PMGR_DEV_DISABLE);
130*e2ad626fSUlf Hansson 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
131*e2ad626fSUlf Hansson 			   APPLE_PMGR_RESET);
132*e2ad626fSUlf Hansson 
133*e2ad626fSUlf Hansson 	spin_unlock_irqrestore(&ps->genpd.slock, flags);
134*e2ad626fSUlf Hansson 
135*e2ad626fSUlf Hansson 	return 0;
136*e2ad626fSUlf Hansson }
137*e2ad626fSUlf Hansson 
apple_pmgr_reset_deassert(struct reset_controller_dev * rcdev,unsigned long id)138*e2ad626fSUlf Hansson static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
139*e2ad626fSUlf Hansson {
140*e2ad626fSUlf Hansson 	struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
141*e2ad626fSUlf Hansson 	unsigned long flags;
142*e2ad626fSUlf Hansson 
143*e2ad626fSUlf Hansson 	spin_lock_irqsave(&ps->genpd.slock, flags);
144*e2ad626fSUlf Hansson 
145*e2ad626fSUlf Hansson 	dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset);
146*e2ad626fSUlf Hansson 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
147*e2ad626fSUlf Hansson 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0);
148*e2ad626fSUlf Hansson 
149*e2ad626fSUlf Hansson 	if (ps->genpd.status == GENPD_STATE_OFF)
150*e2ad626fSUlf Hansson 		dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset);
151*e2ad626fSUlf Hansson 
152*e2ad626fSUlf Hansson 	spin_unlock_irqrestore(&ps->genpd.slock, flags);
153*e2ad626fSUlf Hansson 
154*e2ad626fSUlf Hansson 	return 0;
155*e2ad626fSUlf Hansson }
156*e2ad626fSUlf Hansson 
apple_pmgr_reset_reset(struct reset_controller_dev * rcdev,unsigned long id)157*e2ad626fSUlf Hansson static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
158*e2ad626fSUlf Hansson {
159*e2ad626fSUlf Hansson 	int ret;
160*e2ad626fSUlf Hansson 
161*e2ad626fSUlf Hansson 	ret = apple_pmgr_reset_assert(rcdev, id);
162*e2ad626fSUlf Hansson 	if (ret)
163*e2ad626fSUlf Hansson 		return ret;
164*e2ad626fSUlf Hansson 
165*e2ad626fSUlf Hansson 	usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME);
166*e2ad626fSUlf Hansson 
167*e2ad626fSUlf Hansson 	return apple_pmgr_reset_deassert(rcdev, id);
168*e2ad626fSUlf Hansson }
169*e2ad626fSUlf Hansson 
apple_pmgr_reset_status(struct reset_controller_dev * rcdev,unsigned long id)170*e2ad626fSUlf Hansson static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
171*e2ad626fSUlf Hansson {
172*e2ad626fSUlf Hansson 	struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
173*e2ad626fSUlf Hansson 	u32 reg = 0;
174*e2ad626fSUlf Hansson 
175*e2ad626fSUlf Hansson 	regmap_read(ps->regmap, ps->offset, &reg);
176*e2ad626fSUlf Hansson 
177*e2ad626fSUlf Hansson 	return !!(reg & APPLE_PMGR_RESET);
178*e2ad626fSUlf Hansson }
179*e2ad626fSUlf Hansson 
180*e2ad626fSUlf Hansson const struct reset_control_ops apple_pmgr_reset_ops = {
181*e2ad626fSUlf Hansson 	.assert		= apple_pmgr_reset_assert,
182*e2ad626fSUlf Hansson 	.deassert	= apple_pmgr_reset_deassert,
183*e2ad626fSUlf Hansson 	.reset		= apple_pmgr_reset_reset,
184*e2ad626fSUlf Hansson 	.status		= apple_pmgr_reset_status,
185*e2ad626fSUlf Hansson };
186*e2ad626fSUlf Hansson 
apple_pmgr_reset_xlate(struct reset_controller_dev * rcdev,const struct of_phandle_args * reset_spec)187*e2ad626fSUlf Hansson static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev,
188*e2ad626fSUlf Hansson 				  const struct of_phandle_args *reset_spec)
189*e2ad626fSUlf Hansson {
190*e2ad626fSUlf Hansson 	return 0;
191*e2ad626fSUlf Hansson }
192*e2ad626fSUlf Hansson 
apple_pmgr_ps_probe(struct platform_device * pdev)193*e2ad626fSUlf Hansson static int apple_pmgr_ps_probe(struct platform_device *pdev)
194*e2ad626fSUlf Hansson {
195*e2ad626fSUlf Hansson 	struct device *dev = &pdev->dev;
196*e2ad626fSUlf Hansson 	struct device_node *node = dev->of_node;
197*e2ad626fSUlf Hansson 	struct apple_pmgr_ps *ps;
198*e2ad626fSUlf Hansson 	struct regmap *regmap;
199*e2ad626fSUlf Hansson 	struct of_phandle_iterator it;
200*e2ad626fSUlf Hansson 	int ret;
201*e2ad626fSUlf Hansson 	const char *name;
202*e2ad626fSUlf Hansson 	bool active;
203*e2ad626fSUlf Hansson 
204*e2ad626fSUlf Hansson 	regmap = syscon_node_to_regmap(node->parent);
205*e2ad626fSUlf Hansson 	if (IS_ERR(regmap))
206*e2ad626fSUlf Hansson 		return PTR_ERR(regmap);
207*e2ad626fSUlf Hansson 
208*e2ad626fSUlf Hansson 	ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL);
209*e2ad626fSUlf Hansson 	if (!ps)
210*e2ad626fSUlf Hansson 		return -ENOMEM;
211*e2ad626fSUlf Hansson 
212*e2ad626fSUlf Hansson 	ps->dev = dev;
213*e2ad626fSUlf Hansson 	ps->regmap = regmap;
214*e2ad626fSUlf Hansson 
215*e2ad626fSUlf Hansson 	ret = of_property_read_string(node, "label", &name);
216*e2ad626fSUlf Hansson 	if (ret < 0) {
217*e2ad626fSUlf Hansson 		dev_err(dev, "missing label property\n");
218*e2ad626fSUlf Hansson 		return ret;
219*e2ad626fSUlf Hansson 	}
220*e2ad626fSUlf Hansson 
221*e2ad626fSUlf Hansson 	ret = of_property_read_u32(node, "reg", &ps->offset);
222*e2ad626fSUlf Hansson 	if (ret < 0) {
223*e2ad626fSUlf Hansson 		dev_err(dev, "missing reg property\n");
224*e2ad626fSUlf Hansson 		return ret;
225*e2ad626fSUlf Hansson 	}
226*e2ad626fSUlf Hansson 
227*e2ad626fSUlf Hansson 	ps->genpd.flags |= GENPD_FLAG_IRQ_SAFE;
228*e2ad626fSUlf Hansson 	ps->genpd.name = name;
229*e2ad626fSUlf Hansson 	ps->genpd.power_on = apple_pmgr_ps_power_on;
230*e2ad626fSUlf Hansson 	ps->genpd.power_off = apple_pmgr_ps_power_off;
231*e2ad626fSUlf Hansson 
232*e2ad626fSUlf Hansson 	ret = of_property_read_u32(node, "apple,min-state", &ps->min_state);
233*e2ad626fSUlf Hansson 	if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE)
234*e2ad626fSUlf Hansson 		regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN,
235*e2ad626fSUlf Hansson 				   FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state));
236*e2ad626fSUlf Hansson 
237*e2ad626fSUlf Hansson 	active = apple_pmgr_ps_is_active(ps);
238*e2ad626fSUlf Hansson 	if (of_property_read_bool(node, "apple,always-on")) {
239*e2ad626fSUlf Hansson 		ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
240*e2ad626fSUlf Hansson 		if (!active) {
241*e2ad626fSUlf Hansson 			dev_warn(dev, "always-on domain %s is not on at boot\n", name);
242*e2ad626fSUlf Hansson 			/* Turn it on so pm_genpd_init does not fail */
243*e2ad626fSUlf Hansson 			active = apple_pmgr_ps_power_on(&ps->genpd) == 0;
244*e2ad626fSUlf Hansson 		}
245*e2ad626fSUlf Hansson 	}
246*e2ad626fSUlf Hansson 
247*e2ad626fSUlf Hansson 	/* Turn on auto-PM if the domain is already on */
248*e2ad626fSUlf Hansson 	if (active)
249*e2ad626fSUlf Hansson 		regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE,
250*e2ad626fSUlf Hansson 				   APPLE_PMGR_AUTO_ENABLE);
251*e2ad626fSUlf Hansson 
252*e2ad626fSUlf Hansson 	ret = pm_genpd_init(&ps->genpd, NULL, !active);
253*e2ad626fSUlf Hansson 	if (ret < 0) {
254*e2ad626fSUlf Hansson 		dev_err(dev, "pm_genpd_init failed\n");
255*e2ad626fSUlf Hansson 		return ret;
256*e2ad626fSUlf Hansson 	}
257*e2ad626fSUlf Hansson 
258*e2ad626fSUlf Hansson 	ret = of_genpd_add_provider_simple(node, &ps->genpd);
259*e2ad626fSUlf Hansson 	if (ret < 0) {
260*e2ad626fSUlf Hansson 		dev_err(dev, "of_genpd_add_provider_simple failed\n");
261*e2ad626fSUlf Hansson 		return ret;
262*e2ad626fSUlf Hansson 	}
263*e2ad626fSUlf Hansson 
264*e2ad626fSUlf Hansson 	of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) {
265*e2ad626fSUlf Hansson 		struct of_phandle_args parent, child;
266*e2ad626fSUlf Hansson 
267*e2ad626fSUlf Hansson 		parent.np = it.node;
268*e2ad626fSUlf Hansson 		parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS);
269*e2ad626fSUlf Hansson 		child.np = node;
270*e2ad626fSUlf Hansson 		child.args_count = 0;
271*e2ad626fSUlf Hansson 		ret = of_genpd_add_subdomain(&parent, &child);
272*e2ad626fSUlf Hansson 
273*e2ad626fSUlf Hansson 		if (ret == -EPROBE_DEFER) {
274*e2ad626fSUlf Hansson 			of_node_put(parent.np);
275*e2ad626fSUlf Hansson 			goto err_remove;
276*e2ad626fSUlf Hansson 		} else if (ret < 0) {
277*e2ad626fSUlf Hansson 			dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n",
278*e2ad626fSUlf Hansson 				ret, it.node->name, node->name);
279*e2ad626fSUlf Hansson 			of_node_put(parent.np);
280*e2ad626fSUlf Hansson 			goto err_remove;
281*e2ad626fSUlf Hansson 		}
282*e2ad626fSUlf Hansson 	}
283*e2ad626fSUlf Hansson 
284*e2ad626fSUlf Hansson 	/*
285*e2ad626fSUlf Hansson 	 * Do not participate in regular PM; parent power domains are handled via the
286*e2ad626fSUlf Hansson 	 * genpd hierarchy.
287*e2ad626fSUlf Hansson 	 */
288*e2ad626fSUlf Hansson 	pm_genpd_remove_device(dev);
289*e2ad626fSUlf Hansson 
290*e2ad626fSUlf Hansson 	ps->rcdev.owner = THIS_MODULE;
291*e2ad626fSUlf Hansson 	ps->rcdev.nr_resets = 1;
292*e2ad626fSUlf Hansson 	ps->rcdev.ops = &apple_pmgr_reset_ops;
293*e2ad626fSUlf Hansson 	ps->rcdev.of_node = dev->of_node;
294*e2ad626fSUlf Hansson 	ps->rcdev.of_reset_n_cells = 0;
295*e2ad626fSUlf Hansson 	ps->rcdev.of_xlate = apple_pmgr_reset_xlate;
296*e2ad626fSUlf Hansson 
297*e2ad626fSUlf Hansson 	ret = devm_reset_controller_register(dev, &ps->rcdev);
298*e2ad626fSUlf Hansson 	if (ret < 0)
299*e2ad626fSUlf Hansson 		goto err_remove;
300*e2ad626fSUlf Hansson 
301*e2ad626fSUlf Hansson 	return 0;
302*e2ad626fSUlf Hansson err_remove:
303*e2ad626fSUlf Hansson 	of_genpd_del_provider(node);
304*e2ad626fSUlf Hansson 	pm_genpd_remove(&ps->genpd);
305*e2ad626fSUlf Hansson 	return ret;
306*e2ad626fSUlf Hansson }
307*e2ad626fSUlf Hansson 
308*e2ad626fSUlf Hansson static const struct of_device_id apple_pmgr_ps_of_match[] = {
309*e2ad626fSUlf Hansson 	{ .compatible = "apple,pmgr-pwrstate" },
310*e2ad626fSUlf Hansson 	{}
311*e2ad626fSUlf Hansson };
312*e2ad626fSUlf Hansson 
313*e2ad626fSUlf Hansson MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match);
314*e2ad626fSUlf Hansson 
315*e2ad626fSUlf Hansson static struct platform_driver apple_pmgr_ps_driver = {
316*e2ad626fSUlf Hansson 	.probe = apple_pmgr_ps_probe,
317*e2ad626fSUlf Hansson 	.driver = {
318*e2ad626fSUlf Hansson 		.name = "apple-pmgr-pwrstate",
319*e2ad626fSUlf Hansson 		.of_match_table = apple_pmgr_ps_of_match,
320*e2ad626fSUlf Hansson 	},
321*e2ad626fSUlf Hansson };
322*e2ad626fSUlf Hansson 
323*e2ad626fSUlf Hansson MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
324*e2ad626fSUlf Hansson MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs");
325*e2ad626fSUlf Hansson 
326*e2ad626fSUlf Hansson module_platform_driver(apple_pmgr_ps_driver);
327