18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Suspend/resume support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2009 MontaVista Software, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/export.h> 148c2ecf20Sopenharmony_ci#include <linux/suspend.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/device.h> 178c2ecf20Sopenharmony_ci#include <linux/of_address.h> 188c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct pmc_regs { 218c2ecf20Sopenharmony_ci __be32 devdisr; 228c2ecf20Sopenharmony_ci __be32 devdisr2; 238c2ecf20Sopenharmony_ci __be32 :32; 248c2ecf20Sopenharmony_ci __be32 :32; 258c2ecf20Sopenharmony_ci __be32 pmcsr; 268c2ecf20Sopenharmony_ci#define PMCSR_SLP (1 << 17) 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct device *pmc_dev; 308c2ecf20Sopenharmony_cistatic struct pmc_regs __iomem *pmc_regs; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int pmc_suspend_enter(suspend_state_t state) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci int ret; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci setbits32(&pmc_regs->pmcsr, PMCSR_SLP); 378c2ecf20Sopenharmony_ci /* At this point, the CPU is asleep. */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* Upon resume, wait for SLP bit to be clear. */ 408c2ecf20Sopenharmony_ci ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0, 418c2ecf20Sopenharmony_ci 10000, 10) ? 0 : -ETIMEDOUT; 428c2ecf20Sopenharmony_ci if (ret) 438c2ecf20Sopenharmony_ci dev_err(pmc_dev, "tired waiting for SLP bit to clear\n"); 448c2ecf20Sopenharmony_ci return ret; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic int pmc_suspend_valid(suspend_state_t state) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (state != PM_SUSPEND_STANDBY) 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci return 1; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops pmc_suspend_ops = { 558c2ecf20Sopenharmony_ci .valid = pmc_suspend_valid, 568c2ecf20Sopenharmony_ci .enter = pmc_suspend_enter, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int pmc_probe(struct platform_device *ofdev) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci pmc_regs = of_iomap(ofdev->dev.of_node, 0); 628c2ecf20Sopenharmony_ci if (!pmc_regs) 638c2ecf20Sopenharmony_ci return -ENOMEM; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pmc_dev = &ofdev->dev; 668c2ecf20Sopenharmony_ci suspend_set_ops(&pmc_suspend_ops); 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic const struct of_device_id pmc_ids[] = { 718c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc8548-pmc", }, 728c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc8641d-pmc", }, 738c2ecf20Sopenharmony_ci { }, 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic struct platform_driver pmc_driver = { 778c2ecf20Sopenharmony_ci .driver = { 788c2ecf20Sopenharmony_ci .name = "fsl-pmc", 798c2ecf20Sopenharmony_ci .of_match_table = pmc_ids, 808c2ecf20Sopenharmony_ci }, 818c2ecf20Sopenharmony_ci .probe = pmc_probe, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cibuiltin_platform_driver(pmc_driver); 85