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