xref: /OK3568_Linux_fs/kernel/arch/powerpc/platforms/83xx/suspend.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * MPC83xx suspend support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: Scott Wood <scottwood@freescale.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/pm.h>
11*4882a593Smuzhiyun #include <linux/types.h>
12*4882a593Smuzhiyun #include <linux/ioport.h>
13*4882a593Smuzhiyun #include <linux/interrupt.h>
14*4882a593Smuzhiyun #include <linux/wait.h>
15*4882a593Smuzhiyun #include <linux/sched/signal.h>
16*4882a593Smuzhiyun #include <linux/kthread.h>
17*4882a593Smuzhiyun #include <linux/freezer.h>
18*4882a593Smuzhiyun #include <linux/suspend.h>
19*4882a593Smuzhiyun #include <linux/fsl_devices.h>
20*4882a593Smuzhiyun #include <linux/of_address.h>
21*4882a593Smuzhiyun #include <linux/of_irq.h>
22*4882a593Smuzhiyun #include <linux/of_platform.h>
23*4882a593Smuzhiyun #include <linux/export.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <asm/reg.h>
26*4882a593Smuzhiyun #include <asm/io.h>
27*4882a593Smuzhiyun #include <asm/time.h>
28*4882a593Smuzhiyun #include <asm/mpc6xx.h>
29*4882a593Smuzhiyun #include <asm/switch_to.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <sysdev/fsl_soc.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define PMCCR1_NEXT_STATE       0x0C /* Next state for power management */
34*4882a593Smuzhiyun #define PMCCR1_NEXT_STATE_SHIFT 2
35*4882a593Smuzhiyun #define PMCCR1_CURR_STATE       0x03 /* Current state for power management*/
36*4882a593Smuzhiyun #define IMMR_SYSCR_OFFSET       0x100
37*4882a593Smuzhiyun #define IMMR_RCW_OFFSET         0x900
38*4882a593Smuzhiyun #define RCW_PCI_HOST            0x80000000
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun void mpc83xx_enter_deep_sleep(phys_addr_t immrbase);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct mpc83xx_pmc {
43*4882a593Smuzhiyun 	u32 config;
44*4882a593Smuzhiyun #define PMCCR_DLPEN 2 /* DDR SDRAM low power enable */
45*4882a593Smuzhiyun #define PMCCR_SLPEN 1 /* System low power enable */
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	u32 event;
48*4882a593Smuzhiyun 	u32 mask;
49*4882a593Smuzhiyun /* All but PMCI are deep-sleep only */
50*4882a593Smuzhiyun #define PMCER_GPIO   0x100
51*4882a593Smuzhiyun #define PMCER_PCI    0x080
52*4882a593Smuzhiyun #define PMCER_USB    0x040
53*4882a593Smuzhiyun #define PMCER_ETSEC1 0x020
54*4882a593Smuzhiyun #define PMCER_ETSEC2 0x010
55*4882a593Smuzhiyun #define PMCER_TIMER  0x008
56*4882a593Smuzhiyun #define PMCER_INT1   0x004
57*4882a593Smuzhiyun #define PMCER_INT2   0x002
58*4882a593Smuzhiyun #define PMCER_PMCI   0x001
59*4882a593Smuzhiyun #define PMCER_ALL    0x1FF
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/* deep-sleep only */
62*4882a593Smuzhiyun 	u32 config1;
63*4882a593Smuzhiyun #define PMCCR1_USE_STATE  0x80000000
64*4882a593Smuzhiyun #define PMCCR1_PME_EN     0x00000080
65*4882a593Smuzhiyun #define PMCCR1_ASSERT_PME 0x00000040
66*4882a593Smuzhiyun #define PMCCR1_POWER_OFF  0x00000020
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	/* deep-sleep only */
69*4882a593Smuzhiyun 	u32 config2;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun struct mpc83xx_rcw {
73*4882a593Smuzhiyun 	u32 rcwlr;
74*4882a593Smuzhiyun 	u32 rcwhr;
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun struct mpc83xx_clock {
78*4882a593Smuzhiyun 	u32 spmr;
79*4882a593Smuzhiyun 	u32 occr;
80*4882a593Smuzhiyun 	u32 sccr;
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun struct mpc83xx_syscr {
84*4882a593Smuzhiyun 	__be32 sgprl;
85*4882a593Smuzhiyun 	__be32 sgprh;
86*4882a593Smuzhiyun 	__be32 spridr;
87*4882a593Smuzhiyun 	__be32 :32;
88*4882a593Smuzhiyun 	__be32 spcr;
89*4882a593Smuzhiyun 	__be32 sicrl;
90*4882a593Smuzhiyun 	__be32 sicrh;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun struct mpc83xx_saved {
94*4882a593Smuzhiyun 	u32 sicrl;
95*4882a593Smuzhiyun 	u32 sicrh;
96*4882a593Smuzhiyun 	u32 sccr;
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun struct pmc_type {
100*4882a593Smuzhiyun 	int has_deep_sleep;
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun static struct platform_device *pmc_dev;
104*4882a593Smuzhiyun static int has_deep_sleep, deep_sleeping;
105*4882a593Smuzhiyun static int pmc_irq;
106*4882a593Smuzhiyun static struct mpc83xx_pmc __iomem *pmc_regs;
107*4882a593Smuzhiyun static struct mpc83xx_clock __iomem *clock_regs;
108*4882a593Smuzhiyun static struct mpc83xx_syscr __iomem *syscr_regs;
109*4882a593Smuzhiyun static struct mpc83xx_saved saved_regs;
110*4882a593Smuzhiyun static int is_pci_agent, wake_from_pci;
111*4882a593Smuzhiyun static phys_addr_t immrbase;
112*4882a593Smuzhiyun static int pci_pm_state;
113*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(agent_wq);
114*4882a593Smuzhiyun 
fsl_deep_sleep(void)115*4882a593Smuzhiyun int fsl_deep_sleep(void)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	return deep_sleeping;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun EXPORT_SYMBOL(fsl_deep_sleep);
120*4882a593Smuzhiyun 
mpc83xx_change_state(void)121*4882a593Smuzhiyun static int mpc83xx_change_state(void)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	u32 curr_state;
124*4882a593Smuzhiyun 	u32 reg_cfg1 = in_be32(&pmc_regs->config1);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (is_pci_agent) {
127*4882a593Smuzhiyun 		pci_pm_state = (reg_cfg1 & PMCCR1_NEXT_STATE) >>
128*4882a593Smuzhiyun 		               PMCCR1_NEXT_STATE_SHIFT;
129*4882a593Smuzhiyun 		curr_state = reg_cfg1 & PMCCR1_CURR_STATE;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 		if (curr_state != pci_pm_state) {
132*4882a593Smuzhiyun 			reg_cfg1 &= ~PMCCR1_CURR_STATE;
133*4882a593Smuzhiyun 			reg_cfg1 |= pci_pm_state;
134*4882a593Smuzhiyun 			out_be32(&pmc_regs->config1, reg_cfg1);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 			wake_up(&agent_wq);
137*4882a593Smuzhiyun 			return 1;
138*4882a593Smuzhiyun 		}
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
pmc_irq_handler(int irq,void * dev_id)144*4882a593Smuzhiyun static irqreturn_t pmc_irq_handler(int irq, void *dev_id)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	u32 event = in_be32(&pmc_regs->event);
147*4882a593Smuzhiyun 	int ret = IRQ_NONE;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (mpc83xx_change_state())
150*4882a593Smuzhiyun 		ret = IRQ_HANDLED;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (event) {
153*4882a593Smuzhiyun 		out_be32(&pmc_regs->event, event);
154*4882a593Smuzhiyun 		ret = IRQ_HANDLED;
155*4882a593Smuzhiyun 	}
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return ret;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
mpc83xx_suspend_restore_regs(void)160*4882a593Smuzhiyun static void mpc83xx_suspend_restore_regs(void)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	out_be32(&syscr_regs->sicrl, saved_regs.sicrl);
163*4882a593Smuzhiyun 	out_be32(&syscr_regs->sicrh, saved_regs.sicrh);
164*4882a593Smuzhiyun 	out_be32(&clock_regs->sccr, saved_regs.sccr);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
mpc83xx_suspend_save_regs(void)167*4882a593Smuzhiyun static void mpc83xx_suspend_save_regs(void)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	saved_regs.sicrl = in_be32(&syscr_regs->sicrl);
170*4882a593Smuzhiyun 	saved_regs.sicrh = in_be32(&syscr_regs->sicrh);
171*4882a593Smuzhiyun 	saved_regs.sccr = in_be32(&clock_regs->sccr);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
mpc83xx_suspend_enter(suspend_state_t state)174*4882a593Smuzhiyun static int mpc83xx_suspend_enter(suspend_state_t state)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	int ret = -EAGAIN;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	/* Don't go to sleep if there's a race where pci_pm_state changes
179*4882a593Smuzhiyun 	 * between the agent thread checking it and the PM code disabling
180*4882a593Smuzhiyun 	 * interrupts.
181*4882a593Smuzhiyun 	 */
182*4882a593Smuzhiyun 	if (wake_from_pci) {
183*4882a593Smuzhiyun 		if (pci_pm_state != (deep_sleeping ? 3 : 2))
184*4882a593Smuzhiyun 			goto out;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		out_be32(&pmc_regs->config1,
187*4882a593Smuzhiyun 		         in_be32(&pmc_regs->config1) | PMCCR1_PME_EN);
188*4882a593Smuzhiyun 	}
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	/* Put the system into low-power mode and the RAM
191*4882a593Smuzhiyun 	 * into self-refresh mode once the core goes to
192*4882a593Smuzhiyun 	 * sleep.
193*4882a593Smuzhiyun 	 */
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	out_be32(&pmc_regs->config, PMCCR_SLPEN | PMCCR_DLPEN);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	/* If it has deep sleep (i.e. it's an 831x or compatible),
198*4882a593Smuzhiyun 	 * disable power to the core upon entering sleep mode.  This will
199*4882a593Smuzhiyun 	 * require going through the boot firmware upon a wakeup event.
200*4882a593Smuzhiyun 	 */
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (deep_sleeping) {
203*4882a593Smuzhiyun 		mpc83xx_suspend_save_regs();
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 		out_be32(&pmc_regs->mask, PMCER_ALL);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		out_be32(&pmc_regs->config1,
208*4882a593Smuzhiyun 		         in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 		enable_kernel_fp();
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 		mpc83xx_enter_deep_sleep(immrbase);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		out_be32(&pmc_regs->config1,
215*4882a593Smuzhiyun 		         in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 		out_be32(&pmc_regs->mask, PMCER_PMCI);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 		mpc83xx_suspend_restore_regs();
220*4882a593Smuzhiyun 	} else {
221*4882a593Smuzhiyun 		out_be32(&pmc_regs->mask, PMCER_PMCI);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		mpc6xx_enter_standby();
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	ret = 0;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun out:
229*4882a593Smuzhiyun 	out_be32(&pmc_regs->config1,
230*4882a593Smuzhiyun 	         in_be32(&pmc_regs->config1) & ~PMCCR1_PME_EN);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return ret;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
mpc83xx_suspend_end(void)235*4882a593Smuzhiyun static void mpc83xx_suspend_end(void)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	deep_sleeping = 0;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
mpc83xx_suspend_valid(suspend_state_t state)240*4882a593Smuzhiyun static int mpc83xx_suspend_valid(suspend_state_t state)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
mpc83xx_suspend_begin(suspend_state_t state)245*4882a593Smuzhiyun static int mpc83xx_suspend_begin(suspend_state_t state)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	switch (state) {
248*4882a593Smuzhiyun 		case PM_SUSPEND_STANDBY:
249*4882a593Smuzhiyun 			deep_sleeping = 0;
250*4882a593Smuzhiyun 			return 0;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 		case PM_SUSPEND_MEM:
253*4882a593Smuzhiyun 			if (has_deep_sleep)
254*4882a593Smuzhiyun 				deep_sleeping = 1;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 			return 0;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 		default:
259*4882a593Smuzhiyun 			return -EINVAL;
260*4882a593Smuzhiyun 	}
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
agent_thread_fn(void * data)263*4882a593Smuzhiyun static int agent_thread_fn(void *data)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	while (1) {
266*4882a593Smuzhiyun 		wait_event_interruptible(agent_wq, pci_pm_state >= 2);
267*4882a593Smuzhiyun 		try_to_freeze();
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 		if (signal_pending(current) || pci_pm_state < 2)
270*4882a593Smuzhiyun 			continue;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		/* With a preemptible kernel (or SMP), this could race with
273*4882a593Smuzhiyun 		 * a userspace-driven suspend request.  It's probably best
274*4882a593Smuzhiyun 		 * to avoid mixing the two with such a configuration (or
275*4882a593Smuzhiyun 		 * else fix it by adding a mutex to state_store that we can
276*4882a593Smuzhiyun 		 * synchronize with).
277*4882a593Smuzhiyun 		 */
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 		wake_from_pci = 1;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 		pm_suspend(pci_pm_state == 3 ? PM_SUSPEND_MEM :
282*4882a593Smuzhiyun 		                               PM_SUSPEND_STANDBY);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		wake_from_pci = 0;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	return 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
mpc83xx_set_agent(void)290*4882a593Smuzhiyun static void mpc83xx_set_agent(void)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	out_be32(&pmc_regs->config1, PMCCR1_USE_STATE);
293*4882a593Smuzhiyun 	out_be32(&pmc_regs->mask, PMCER_PMCI);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	kthread_run(agent_thread_fn, NULL, "PCI power mgt");
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
mpc83xx_is_pci_agent(void)298*4882a593Smuzhiyun static int mpc83xx_is_pci_agent(void)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	struct mpc83xx_rcw __iomem *rcw_regs;
301*4882a593Smuzhiyun 	int ret;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	rcw_regs = ioremap(get_immrbase() + IMMR_RCW_OFFSET,
304*4882a593Smuzhiyun 	                   sizeof(struct mpc83xx_rcw));
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	if (!rcw_regs)
307*4882a593Smuzhiyun 		return -ENOMEM;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	ret = !(in_be32(&rcw_regs->rcwhr) & RCW_PCI_HOST);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	iounmap(rcw_regs);
312*4882a593Smuzhiyun 	return ret;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun static const struct platform_suspend_ops mpc83xx_suspend_ops = {
316*4882a593Smuzhiyun 	.valid = mpc83xx_suspend_valid,
317*4882a593Smuzhiyun 	.begin = mpc83xx_suspend_begin,
318*4882a593Smuzhiyun 	.enter = mpc83xx_suspend_enter,
319*4882a593Smuzhiyun 	.end = mpc83xx_suspend_end,
320*4882a593Smuzhiyun };
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun static const struct of_device_id pmc_match[];
pmc_probe(struct platform_device * ofdev)323*4882a593Smuzhiyun static int pmc_probe(struct platform_device *ofdev)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	const struct of_device_id *match;
326*4882a593Smuzhiyun 	struct device_node *np = ofdev->dev.of_node;
327*4882a593Smuzhiyun 	struct resource res;
328*4882a593Smuzhiyun 	const struct pmc_type *type;
329*4882a593Smuzhiyun 	int ret = 0;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	match = of_match_device(pmc_match, &ofdev->dev);
332*4882a593Smuzhiyun 	if (!match)
333*4882a593Smuzhiyun 		return -EINVAL;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	type = match->data;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	if (!of_device_is_available(np))
338*4882a593Smuzhiyun 		return -ENODEV;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	has_deep_sleep = type->has_deep_sleep;
341*4882a593Smuzhiyun 	immrbase = get_immrbase();
342*4882a593Smuzhiyun 	pmc_dev = ofdev;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	is_pci_agent = mpc83xx_is_pci_agent();
345*4882a593Smuzhiyun 	if (is_pci_agent < 0)
346*4882a593Smuzhiyun 		return is_pci_agent;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	ret = of_address_to_resource(np, 0, &res);
349*4882a593Smuzhiyun 	if (ret)
350*4882a593Smuzhiyun 		return -ENODEV;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	pmc_irq = irq_of_parse_and_map(np, 0);
353*4882a593Smuzhiyun 	if (pmc_irq) {
354*4882a593Smuzhiyun 		ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED,
355*4882a593Smuzhiyun 		                  "pmc", ofdev);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		if (ret)
358*4882a593Smuzhiyun 			return -EBUSY;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	pmc_regs = ioremap(res.start, sizeof(*pmc_regs));
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (!pmc_regs) {
364*4882a593Smuzhiyun 		ret = -ENOMEM;
365*4882a593Smuzhiyun 		goto out;
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	ret = of_address_to_resource(np, 1, &res);
369*4882a593Smuzhiyun 	if (ret) {
370*4882a593Smuzhiyun 		ret = -ENODEV;
371*4882a593Smuzhiyun 		goto out_pmc;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	clock_regs = ioremap(res.start, sizeof(*clock_regs));
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (!clock_regs) {
377*4882a593Smuzhiyun 		ret = -ENOMEM;
378*4882a593Smuzhiyun 		goto out_pmc;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (has_deep_sleep) {
382*4882a593Smuzhiyun 		syscr_regs = ioremap(immrbase + IMMR_SYSCR_OFFSET,
383*4882a593Smuzhiyun 				     sizeof(*syscr_regs));
384*4882a593Smuzhiyun 		if (!syscr_regs) {
385*4882a593Smuzhiyun 			ret = -ENOMEM;
386*4882a593Smuzhiyun 			goto out_syscr;
387*4882a593Smuzhiyun 		}
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (is_pci_agent)
391*4882a593Smuzhiyun 		mpc83xx_set_agent();
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	suspend_set_ops(&mpc83xx_suspend_ops);
394*4882a593Smuzhiyun 	return 0;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun out_syscr:
397*4882a593Smuzhiyun 	iounmap(clock_regs);
398*4882a593Smuzhiyun out_pmc:
399*4882a593Smuzhiyun 	iounmap(pmc_regs);
400*4882a593Smuzhiyun out:
401*4882a593Smuzhiyun 	if (pmc_irq)
402*4882a593Smuzhiyun 		free_irq(pmc_irq, ofdev);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	return ret;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
pmc_remove(struct platform_device * ofdev)407*4882a593Smuzhiyun static int pmc_remove(struct platform_device *ofdev)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	return -EPERM;
410*4882a593Smuzhiyun };
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun static struct pmc_type pmc_types[] = {
413*4882a593Smuzhiyun 	{
414*4882a593Smuzhiyun 		.has_deep_sleep = 1,
415*4882a593Smuzhiyun 	},
416*4882a593Smuzhiyun 	{
417*4882a593Smuzhiyun 		.has_deep_sleep = 0,
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun };
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun static const struct of_device_id pmc_match[] = {
422*4882a593Smuzhiyun 	{
423*4882a593Smuzhiyun 		.compatible = "fsl,mpc8313-pmc",
424*4882a593Smuzhiyun 		.data = &pmc_types[0],
425*4882a593Smuzhiyun 	},
426*4882a593Smuzhiyun 	{
427*4882a593Smuzhiyun 		.compatible = "fsl,mpc8349-pmc",
428*4882a593Smuzhiyun 		.data = &pmc_types[1],
429*4882a593Smuzhiyun 	},
430*4882a593Smuzhiyun 	{}
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun static struct platform_driver pmc_driver = {
434*4882a593Smuzhiyun 	.driver = {
435*4882a593Smuzhiyun 		.name = "mpc83xx-pmc",
436*4882a593Smuzhiyun 		.of_match_table = pmc_match,
437*4882a593Smuzhiyun 	},
438*4882a593Smuzhiyun 	.probe = pmc_probe,
439*4882a593Smuzhiyun 	.remove = pmc_remove
440*4882a593Smuzhiyun };
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun builtin_platform_driver(pmc_driver);
443