1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ 3 4 #include <linux/kernel.h> 5 #include <linux/interrupt.h> 6 #include <linux/pm_runtime.h> 7 #include "cc_driver.h" 8 #include "cc_buffer_mgr.h" 9 #include "cc_request_mgr.h" 10 #include "cc_sram_mgr.h" 11 #include "cc_ivgen.h" 12 #include "cc_pm.h" 13 14 #define POWER_DOWN_ENABLE 0x01 15 #define POWER_DOWN_DISABLE 0x00 16 17 const struct dev_pm_ops ccree_pm = { 18 SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL) 19 }; 20 21 int cc_pm_suspend(struct device *dev) 22 { 23 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 24 int rc; 25 26 dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); 27 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); 28 rc = cc_suspend_req_queue(drvdata); 29 if (rc) { 30 dev_err(dev, "cc_suspend_req_queue (%x)\n", rc); 31 return rc; 32 } 33 fini_cc_regs(drvdata); 34 cc_clk_off(drvdata); 35 return 0; 36 } 37 38 int cc_pm_resume(struct device *dev) 39 { 40 int rc; 41 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 42 43 dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n"); 44 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); 45 46 rc = cc_clk_on(drvdata); 47 if (rc) { 48 dev_err(dev, "failed getting clock back on. We're toast.\n"); 49 return rc; 50 } 51 52 rc = init_cc_regs(drvdata, false); 53 if (rc) { 54 dev_err(dev, "init_cc_regs (%x)\n", rc); 55 return rc; 56 } 57 58 rc = cc_resume_req_queue(drvdata); 59 if (rc) { 60 dev_err(dev, "cc_resume_req_queue (%x)\n", rc); 61 return rc; 62 } 63 64 cc_init_iv_sram(drvdata); 65 return 0; 66 } 67 68 int cc_pm_get(struct device *dev) 69 { 70 int rc = 0; 71 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 72 73 if (cc_req_queue_suspended(drvdata)) 74 rc = pm_runtime_get_sync(dev); 75 else 76 pm_runtime_get_noresume(dev); 77 78 return rc; 79 } 80 81 int cc_pm_put_suspend(struct device *dev) 82 { 83 int rc = 0; 84 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 85 86 if (!cc_req_queue_suspended(drvdata)) { 87 pm_runtime_mark_last_busy(dev); 88 rc = pm_runtime_put_autosuspend(dev); 89 } else { 90 /* Something wrong happens*/ 91 dev_err(dev, "request to suspend already suspended queue"); 92 rc = -EBUSY; 93 } 94 return rc; 95 } 96 97 int cc_pm_init(struct cc_drvdata *drvdata) 98 { 99 int rc = 0; 100 struct device *dev = drvdata_to_dev(drvdata); 101 102 /* must be before the enabling to avoid resdundent suspending */ 103 pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT); 104 pm_runtime_use_autosuspend(dev); 105 /* activate the PM module */ 106 rc = pm_runtime_set_active(dev); 107 if (rc) 108 return rc; 109 /* enable the PM module*/ 110 pm_runtime_enable(dev); 111 112 return rc; 113 } 114 115 void cc_pm_fini(struct cc_drvdata *drvdata) 116 { 117 pm_runtime_disable(drvdata_to_dev(drvdata)); 118 } 119