162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MPC83xx suspend support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Scott Wood <scottwood@freescale.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2006-2007 Freescale Semiconductor, Inc. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/pm.h> 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci#include <linux/ioport.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/wait.h> 1562306a36Sopenharmony_ci#include <linux/sched/signal.h> 1662306a36Sopenharmony_ci#include <linux/kthread.h> 1762306a36Sopenharmony_ci#include <linux/freezer.h> 1862306a36Sopenharmony_ci#include <linux/suspend.h> 1962306a36Sopenharmony_ci#include <linux/fsl_devices.h> 2062306a36Sopenharmony_ci#include <linux/of_address.h> 2162306a36Sopenharmony_ci#include <linux/of_irq.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/export.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <asm/reg.h> 2662306a36Sopenharmony_ci#include <asm/io.h> 2762306a36Sopenharmony_ci#include <asm/time.h> 2862306a36Sopenharmony_ci#include <asm/mpc6xx.h> 2962306a36Sopenharmony_ci#include <asm/switch_to.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define PMCCR1_NEXT_STATE 0x0C /* Next state for power management */ 3462306a36Sopenharmony_ci#define PMCCR1_NEXT_STATE_SHIFT 2 3562306a36Sopenharmony_ci#define PMCCR1_CURR_STATE 0x03 /* Current state for power management*/ 3662306a36Sopenharmony_ci#define IMMR_SYSCR_OFFSET 0x100 3762306a36Sopenharmony_ci#define IMMR_RCW_OFFSET 0x900 3862306a36Sopenharmony_ci#define RCW_PCI_HOST 0x80000000 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid mpc83xx_enter_deep_sleep(phys_addr_t immrbase); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct mpc83xx_pmc { 4362306a36Sopenharmony_ci u32 config; 4462306a36Sopenharmony_ci#define PMCCR_DLPEN 2 /* DDR SDRAM low power enable */ 4562306a36Sopenharmony_ci#define PMCCR_SLPEN 1 /* System low power enable */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci u32 event; 4862306a36Sopenharmony_ci u32 mask; 4962306a36Sopenharmony_ci/* All but PMCI are deep-sleep only */ 5062306a36Sopenharmony_ci#define PMCER_GPIO 0x100 5162306a36Sopenharmony_ci#define PMCER_PCI 0x080 5262306a36Sopenharmony_ci#define PMCER_USB 0x040 5362306a36Sopenharmony_ci#define PMCER_ETSEC1 0x020 5462306a36Sopenharmony_ci#define PMCER_ETSEC2 0x010 5562306a36Sopenharmony_ci#define PMCER_TIMER 0x008 5662306a36Sopenharmony_ci#define PMCER_INT1 0x004 5762306a36Sopenharmony_ci#define PMCER_INT2 0x002 5862306a36Sopenharmony_ci#define PMCER_PMCI 0x001 5962306a36Sopenharmony_ci#define PMCER_ALL 0x1FF 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* deep-sleep only */ 6262306a36Sopenharmony_ci u32 config1; 6362306a36Sopenharmony_ci#define PMCCR1_USE_STATE 0x80000000 6462306a36Sopenharmony_ci#define PMCCR1_PME_EN 0x00000080 6562306a36Sopenharmony_ci#define PMCCR1_ASSERT_PME 0x00000040 6662306a36Sopenharmony_ci#define PMCCR1_POWER_OFF 0x00000020 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* deep-sleep only */ 6962306a36Sopenharmony_ci u32 config2; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct mpc83xx_rcw { 7362306a36Sopenharmony_ci u32 rcwlr; 7462306a36Sopenharmony_ci u32 rcwhr; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct mpc83xx_clock { 7862306a36Sopenharmony_ci u32 spmr; 7962306a36Sopenharmony_ci u32 occr; 8062306a36Sopenharmony_ci u32 sccr; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct mpc83xx_syscr { 8462306a36Sopenharmony_ci __be32 sgprl; 8562306a36Sopenharmony_ci __be32 sgprh; 8662306a36Sopenharmony_ci __be32 spridr; 8762306a36Sopenharmony_ci __be32 :32; 8862306a36Sopenharmony_ci __be32 spcr; 8962306a36Sopenharmony_ci __be32 sicrl; 9062306a36Sopenharmony_ci __be32 sicrh; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistruct mpc83xx_saved { 9462306a36Sopenharmony_ci u32 sicrl; 9562306a36Sopenharmony_ci u32 sicrh; 9662306a36Sopenharmony_ci u32 sccr; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistruct pmc_type { 10062306a36Sopenharmony_ci int has_deep_sleep; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int has_deep_sleep, deep_sleeping; 10462306a36Sopenharmony_cistatic int pmc_irq; 10562306a36Sopenharmony_cistatic struct mpc83xx_pmc __iomem *pmc_regs; 10662306a36Sopenharmony_cistatic struct mpc83xx_clock __iomem *clock_regs; 10762306a36Sopenharmony_cistatic struct mpc83xx_syscr __iomem *syscr_regs; 10862306a36Sopenharmony_cistatic struct mpc83xx_saved saved_regs; 10962306a36Sopenharmony_cistatic int is_pci_agent, wake_from_pci; 11062306a36Sopenharmony_cistatic phys_addr_t immrbase; 11162306a36Sopenharmony_cistatic int pci_pm_state; 11262306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(agent_wq); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciint fsl_deep_sleep(void) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return deep_sleeping; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL(fsl_deep_sleep); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int mpc83xx_change_state(void) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci u32 curr_state; 12362306a36Sopenharmony_ci u32 reg_cfg1 = in_be32(&pmc_regs->config1); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (is_pci_agent) { 12662306a36Sopenharmony_ci pci_pm_state = (reg_cfg1 & PMCCR1_NEXT_STATE) >> 12762306a36Sopenharmony_ci PMCCR1_NEXT_STATE_SHIFT; 12862306a36Sopenharmony_ci curr_state = reg_cfg1 & PMCCR1_CURR_STATE; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (curr_state != pci_pm_state) { 13162306a36Sopenharmony_ci reg_cfg1 &= ~PMCCR1_CURR_STATE; 13262306a36Sopenharmony_ci reg_cfg1 |= pci_pm_state; 13362306a36Sopenharmony_ci out_be32(&pmc_regs->config1, reg_cfg1); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci wake_up(&agent_wq); 13662306a36Sopenharmony_ci return 1; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic irqreturn_t pmc_irq_handler(int irq, void *dev_id) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci u32 event = in_be32(&pmc_regs->event); 14662306a36Sopenharmony_ci int ret = IRQ_NONE; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (mpc83xx_change_state()) 14962306a36Sopenharmony_ci ret = IRQ_HANDLED; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (event) { 15262306a36Sopenharmony_ci out_be32(&pmc_regs->event, event); 15362306a36Sopenharmony_ci ret = IRQ_HANDLED; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return ret; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void mpc83xx_suspend_restore_regs(void) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci out_be32(&syscr_regs->sicrl, saved_regs.sicrl); 16262306a36Sopenharmony_ci out_be32(&syscr_regs->sicrh, saved_regs.sicrh); 16362306a36Sopenharmony_ci out_be32(&clock_regs->sccr, saved_regs.sccr); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void mpc83xx_suspend_save_regs(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci saved_regs.sicrl = in_be32(&syscr_regs->sicrl); 16962306a36Sopenharmony_ci saved_regs.sicrh = in_be32(&syscr_regs->sicrh); 17062306a36Sopenharmony_ci saved_regs.sccr = in_be32(&clock_regs->sccr); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int mpc83xx_suspend_enter(suspend_state_t state) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci int ret = -EAGAIN; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Don't go to sleep if there's a race where pci_pm_state changes 17862306a36Sopenharmony_ci * between the agent thread checking it and the PM code disabling 17962306a36Sopenharmony_ci * interrupts. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci if (wake_from_pci) { 18262306a36Sopenharmony_ci if (pci_pm_state != (deep_sleeping ? 3 : 2)) 18362306a36Sopenharmony_ci goto out; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci out_be32(&pmc_regs->config1, 18662306a36Sopenharmony_ci in_be32(&pmc_regs->config1) | PMCCR1_PME_EN); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Put the system into low-power mode and the RAM 19062306a36Sopenharmony_ci * into self-refresh mode once the core goes to 19162306a36Sopenharmony_ci * sleep. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci out_be32(&pmc_regs->config, PMCCR_SLPEN | PMCCR_DLPEN); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* If it has deep sleep (i.e. it's an 831x or compatible), 19762306a36Sopenharmony_ci * disable power to the core upon entering sleep mode. This will 19862306a36Sopenharmony_ci * require going through the boot firmware upon a wakeup event. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (deep_sleeping) { 20262306a36Sopenharmony_ci mpc83xx_suspend_save_regs(); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci out_be32(&pmc_regs->mask, PMCER_ALL); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci out_be32(&pmc_regs->config1, 20762306a36Sopenharmony_ci in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci enable_kernel_fp(); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci mpc83xx_enter_deep_sleep(immrbase); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci out_be32(&pmc_regs->config1, 21462306a36Sopenharmony_ci in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci out_be32(&pmc_regs->mask, PMCER_PMCI); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci mpc83xx_suspend_restore_regs(); 21962306a36Sopenharmony_ci } else { 22062306a36Sopenharmony_ci out_be32(&pmc_regs->mask, PMCER_PMCI); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mpc6xx_enter_standby(); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciout: 22862306a36Sopenharmony_ci out_be32(&pmc_regs->config1, 22962306a36Sopenharmony_ci in_be32(&pmc_regs->config1) & ~PMCCR1_PME_EN); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void mpc83xx_suspend_end(void) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci deep_sleeping = 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int mpc83xx_suspend_valid(suspend_state_t state) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int mpc83xx_suspend_begin(suspend_state_t state) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci switch (state) { 24762306a36Sopenharmony_ci case PM_SUSPEND_STANDBY: 24862306a36Sopenharmony_ci deep_sleeping = 0; 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci case PM_SUSPEND_MEM: 25262306a36Sopenharmony_ci if (has_deep_sleep) 25362306a36Sopenharmony_ci deep_sleeping = 1; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci return -EINVAL; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int agent_thread_fn(void *data) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci while (1) { 26562306a36Sopenharmony_ci wait_event_interruptible(agent_wq, pci_pm_state >= 2); 26662306a36Sopenharmony_ci try_to_freeze(); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (signal_pending(current) || pci_pm_state < 2) 26962306a36Sopenharmony_ci continue; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* With a preemptible kernel (or SMP), this could race with 27262306a36Sopenharmony_ci * a userspace-driven suspend request. It's probably best 27362306a36Sopenharmony_ci * to avoid mixing the two with such a configuration (or 27462306a36Sopenharmony_ci * else fix it by adding a mutex to state_store that we can 27562306a36Sopenharmony_ci * synchronize with). 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci wake_from_pci = 1; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci pm_suspend(pci_pm_state == 3 ? PM_SUSPEND_MEM : 28162306a36Sopenharmony_ci PM_SUSPEND_STANDBY); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci wake_from_pci = 0; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void mpc83xx_set_agent(void) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci out_be32(&pmc_regs->config1, PMCCR1_USE_STATE); 29262306a36Sopenharmony_ci out_be32(&pmc_regs->mask, PMCER_PMCI); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci kthread_run(agent_thread_fn, NULL, "PCI power mgt"); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int mpc83xx_is_pci_agent(void) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct mpc83xx_rcw __iomem *rcw_regs; 30062306a36Sopenharmony_ci int ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci rcw_regs = ioremap(get_immrbase() + IMMR_RCW_OFFSET, 30362306a36Sopenharmony_ci sizeof(struct mpc83xx_rcw)); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!rcw_regs) 30662306a36Sopenharmony_ci return -ENOMEM; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci ret = !(in_be32(&rcw_regs->rcwhr) & RCW_PCI_HOST); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci iounmap(rcw_regs); 31162306a36Sopenharmony_ci return ret; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic const struct platform_suspend_ops mpc83xx_suspend_ops = { 31562306a36Sopenharmony_ci .valid = mpc83xx_suspend_valid, 31662306a36Sopenharmony_ci .begin = mpc83xx_suspend_begin, 31762306a36Sopenharmony_ci .enter = mpc83xx_suspend_enter, 31862306a36Sopenharmony_ci .end = mpc83xx_suspend_end, 31962306a36Sopenharmony_ci}; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic struct pmc_type pmc_types[] = { 32262306a36Sopenharmony_ci { 32362306a36Sopenharmony_ci .has_deep_sleep = 1, 32462306a36Sopenharmony_ci }, 32562306a36Sopenharmony_ci { 32662306a36Sopenharmony_ci .has_deep_sleep = 0, 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci}; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic const struct of_device_id pmc_match[] = { 33162306a36Sopenharmony_ci { 33262306a36Sopenharmony_ci .compatible = "fsl,mpc8313-pmc", 33362306a36Sopenharmony_ci .data = &pmc_types[0], 33462306a36Sopenharmony_ci }, 33562306a36Sopenharmony_ci { 33662306a36Sopenharmony_ci .compatible = "fsl,mpc8349-pmc", 33762306a36Sopenharmony_ci .data = &pmc_types[1], 33862306a36Sopenharmony_ci }, 33962306a36Sopenharmony_ci {} 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int pmc_probe(struct platform_device *ofdev) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 34562306a36Sopenharmony_ci struct resource res; 34662306a36Sopenharmony_ci const struct pmc_type *type; 34762306a36Sopenharmony_ci int ret = 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci type = of_device_get_match_data(&ofdev->dev); 35062306a36Sopenharmony_ci if (!type) 35162306a36Sopenharmony_ci return -EINVAL; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (!of_device_is_available(np)) 35462306a36Sopenharmony_ci return -ENODEV; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci has_deep_sleep = type->has_deep_sleep; 35762306a36Sopenharmony_ci immrbase = get_immrbase(); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci is_pci_agent = mpc83xx_is_pci_agent(); 36062306a36Sopenharmony_ci if (is_pci_agent < 0) 36162306a36Sopenharmony_ci return is_pci_agent; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ret = of_address_to_resource(np, 0, &res); 36462306a36Sopenharmony_ci if (ret) 36562306a36Sopenharmony_ci return -ENODEV; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci pmc_irq = irq_of_parse_and_map(np, 0); 36862306a36Sopenharmony_ci if (pmc_irq) { 36962306a36Sopenharmony_ci ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED, 37062306a36Sopenharmony_ci "pmc", ofdev); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (ret) 37362306a36Sopenharmony_ci return -EBUSY; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci pmc_regs = ioremap(res.start, sizeof(*pmc_regs)); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!pmc_regs) { 37962306a36Sopenharmony_ci ret = -ENOMEM; 38062306a36Sopenharmony_ci goto out; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = of_address_to_resource(np, 1, &res); 38462306a36Sopenharmony_ci if (ret) { 38562306a36Sopenharmony_ci ret = -ENODEV; 38662306a36Sopenharmony_ci goto out_pmc; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci clock_regs = ioremap(res.start, sizeof(*clock_regs)); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (!clock_regs) { 39262306a36Sopenharmony_ci ret = -ENOMEM; 39362306a36Sopenharmony_ci goto out_pmc; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (has_deep_sleep) { 39762306a36Sopenharmony_ci syscr_regs = ioremap(immrbase + IMMR_SYSCR_OFFSET, 39862306a36Sopenharmony_ci sizeof(*syscr_regs)); 39962306a36Sopenharmony_ci if (!syscr_regs) { 40062306a36Sopenharmony_ci ret = -ENOMEM; 40162306a36Sopenharmony_ci goto out_syscr; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (is_pci_agent) 40662306a36Sopenharmony_ci mpc83xx_set_agent(); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci suspend_set_ops(&mpc83xx_suspend_ops); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ciout_syscr: 41262306a36Sopenharmony_ci iounmap(clock_regs); 41362306a36Sopenharmony_ciout_pmc: 41462306a36Sopenharmony_ci iounmap(pmc_regs); 41562306a36Sopenharmony_ciout: 41662306a36Sopenharmony_ci if (pmc_irq) 41762306a36Sopenharmony_ci free_irq(pmc_irq, ofdev); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic struct platform_driver pmc_driver = { 42362306a36Sopenharmony_ci .driver = { 42462306a36Sopenharmony_ci .name = "mpc83xx-pmc", 42562306a36Sopenharmony_ci .of_match_table = pmc_match, 42662306a36Sopenharmony_ci .suppress_bind_attrs = true, 42762306a36Sopenharmony_ci }, 42862306a36Sopenharmony_ci .probe = pmc_probe, 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cibuiltin_platform_driver(pmc_driver); 432