1/* 2 * arch/sh/kernel/cpu/shmobile/pm_runtime.c 3 * 4 * Runtime PM support code for SuperH Mobile 5 * 6 * Copyright (C) 2009 Magnus Damm 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/io.h> 15#include <linux/pm_runtime.h> 16#include <linux/platform_device.h> 17#include <linux/mutex.h> 18#include <asm/hwblk.h> 19 20static DEFINE_SPINLOCK(hwblk_lock); 21static LIST_HEAD(hwblk_idle_list); 22static struct work_struct hwblk_work; 23 24extern struct hwblk_info *hwblk_info; 25 26static void platform_pm_runtime_not_idle(struct platform_device *pdev) 27{ 28 unsigned long flags; 29 30 /* remove device from idle list */ 31 spin_lock_irqsave(&hwblk_lock, flags); 32 if (test_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags)) { 33 list_del(&pdev->archdata.entry); 34 __clear_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags); 35 } 36 spin_unlock_irqrestore(&hwblk_lock, flags); 37} 38 39static int __platform_pm_runtime_resume(struct platform_device *pdev) 40{ 41 struct device *d = &pdev->dev; 42 struct pdev_archdata *ad = &pdev->archdata; 43 int hwblk = ad->hwblk_id; 44 int ret = -ENOSYS; 45 46 dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk); 47 48 if (d->driver) { 49 hwblk_enable(hwblk_info, hwblk); 50 ret = 0; 51 52 if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) { 53 if (d->driver->pm && d->driver->pm->runtime_resume) 54 ret = d->driver->pm->runtime_resume(d); 55 56 if (!ret) 57 clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); 58 else 59 hwblk_disable(hwblk_info, hwblk); 60 } 61 } 62 63 dev_dbg(d, "__platform_pm_runtime_resume() [%d] - returns %d\n", 64 hwblk, ret); 65 66 return ret; 67} 68 69static int __platform_pm_runtime_suspend(struct platform_device *pdev) 70{ 71 struct device *d = &pdev->dev; 72 struct pdev_archdata *ad = &pdev->archdata; 73 int hwblk = ad->hwblk_id; 74 int ret = -ENOSYS; 75 76 dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk); 77 78 if (d->driver) { 79 BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags)); 80 ret = 0; 81 82 if (d->driver->pm && d->driver->pm->runtime_suspend) { 83 hwblk_enable(hwblk_info, hwblk); 84 ret = d->driver->pm->runtime_suspend(d); 85 hwblk_disable(hwblk_info, hwblk); 86 } 87 88 if (!ret) { 89 set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); 90 platform_pm_runtime_not_idle(pdev); 91 hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE); 92 } 93 } 94 95 dev_dbg(d, "__platform_pm_runtime_suspend() [%d] - returns %d\n", 96 hwblk, ret); 97 98 return ret; 99} 100 101static void platform_pm_runtime_work(struct work_struct *work) 102{ 103 struct platform_device *pdev; 104 unsigned long flags; 105 int ret; 106 107 /* go through the idle list and suspend one device at a time */ 108 do { 109 spin_lock_irqsave(&hwblk_lock, flags); 110 if (list_empty(&hwblk_idle_list)) 111 pdev = NULL; 112 else 113 pdev = list_first_entry(&hwblk_idle_list, 114 struct platform_device, 115 archdata.entry); 116 spin_unlock_irqrestore(&hwblk_lock, flags); 117 118 if (pdev) { 119 mutex_lock(&pdev->archdata.mutex); 120 ret = __platform_pm_runtime_suspend(pdev); 121 122 /* at this point the platform device may be: 123 * suspended: ret = 0, FLAG_SUSP set, clock stopped 124 * failed: ret < 0, FLAG_IDLE set, clock stopped 125 */ 126 mutex_unlock(&pdev->archdata.mutex); 127 } else { 128 ret = -ENODEV; 129 } 130 } while (!ret); 131} 132 133/* this function gets called from cpuidle context when all devices in the 134 * main power domain are unused but some are counted as idle, ie the hwblk 135 * counter values are (HWBLK_CNT_USAGE == 0) && (HWBLK_CNT_IDLE != 0) 136 */ 137void platform_pm_runtime_suspend_idle(void) 138{ 139 queue_work(pm_wq, &hwblk_work); 140} 141 142int platform_pm_runtime_suspend(struct device *dev) 143{ 144 struct platform_device *pdev = to_platform_device(dev); 145 struct pdev_archdata *ad = &pdev->archdata; 146 unsigned long flags; 147 int hwblk = ad->hwblk_id; 148 int ret = 0; 149 150 dev_dbg(dev, "platform_pm_runtime_suspend() [%d]\n", hwblk); 151 152 /* ignore off-chip platform devices */ 153 if (!hwblk) 154 goto out; 155 156 /* interrupt context not allowed */ 157 might_sleep(); 158 159 /* catch misconfigured drivers not starting with resume */ 160 if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags)) { 161 ret = -EINVAL; 162 goto out; 163 } 164 165 /* serialize */ 166 mutex_lock(&ad->mutex); 167 168 /* disable clock */ 169 hwblk_disable(hwblk_info, hwblk); 170 171 /* put device on idle list */ 172 spin_lock_irqsave(&hwblk_lock, flags); 173 list_add_tail(&pdev->archdata.entry, &hwblk_idle_list); 174 __set_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags); 175 spin_unlock_irqrestore(&hwblk_lock, flags); 176 177 /* increase idle count */ 178 hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_IDLE); 179 180 /* at this point the platform device is: 181 * idle: ret = 0, FLAG_IDLE set, clock stopped 182 */ 183 mutex_unlock(&ad->mutex); 184 185out: 186 dev_dbg(dev, "platform_pm_runtime_suspend() [%d] returns %d\n", 187 hwblk, ret); 188 189 return ret; 190} 191 192int platform_pm_runtime_resume(struct device *dev) 193{ 194 struct platform_device *pdev = to_platform_device(dev); 195 struct pdev_archdata *ad = &pdev->archdata; 196 int hwblk = ad->hwblk_id; 197 int ret = 0; 198 199 dev_dbg(dev, "platform_pm_runtime_resume() [%d]\n", hwblk); 200 201 /* ignore off-chip platform devices */ 202 if (!hwblk) 203 goto out; 204 205 /* interrupt context not allowed */ 206 might_sleep(); 207 208 /* serialize */ 209 mutex_lock(&ad->mutex); 210 211 /* make sure device is removed from idle list */ 212 platform_pm_runtime_not_idle(pdev); 213 214 /* decrease idle count */ 215 if (!test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags) && 216 !test_bit(PDEV_ARCHDATA_FLAG_SUSP, &pdev->archdata.flags)) 217 hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE); 218 219 /* resume the device if needed */ 220 ret = __platform_pm_runtime_resume(pdev); 221 222 /* the driver has been initialized now, so clear the init flag */ 223 clear_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); 224 225 /* at this point the platform device may be: 226 * resumed: ret = 0, flags = 0, clock started 227 * failed: ret < 0, FLAG_SUSP set, clock stopped 228 */ 229 mutex_unlock(&ad->mutex); 230out: 231 dev_dbg(dev, "platform_pm_runtime_resume() [%d] returns %d\n", 232 hwblk, ret); 233 234 return ret; 235} 236 237int platform_pm_runtime_idle(struct device *dev) 238{ 239 struct platform_device *pdev = to_platform_device(dev); 240 int hwblk = pdev->archdata.hwblk_id; 241 int ret = 0; 242 243 dev_dbg(dev, "platform_pm_runtime_idle() [%d]\n", hwblk); 244 245 /* ignore off-chip platform devices */ 246 if (!hwblk) 247 goto out; 248 249 /* interrupt context not allowed, use pm_runtime_put()! */ 250 might_sleep(); 251 252 /* suspend synchronously to disable clocks immediately */ 253 ret = pm_runtime_suspend(dev); 254out: 255 dev_dbg(dev, "platform_pm_runtime_idle() [%d] done!\n", hwblk); 256 return ret; 257} 258 259static int platform_bus_notify(struct notifier_block *nb, 260 unsigned long action, void *data) 261{ 262 struct device *dev = data; 263 struct platform_device *pdev = to_platform_device(dev); 264 int hwblk = pdev->archdata.hwblk_id; 265 266 /* ignore off-chip platform devices */ 267 if (!hwblk) 268 return 0; 269 270 switch (action) { 271 case BUS_NOTIFY_ADD_DEVICE: 272 INIT_LIST_HEAD(&pdev->archdata.entry); 273 mutex_init(&pdev->archdata.mutex); 274 /* platform devices without drivers should be disabled */ 275 hwblk_enable(hwblk_info, hwblk); 276 hwblk_disable(hwblk_info, hwblk); 277 /* make sure driver re-inits itself once */ 278 __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); 279 break; 280 /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */ 281 case BUS_NOTIFY_BOUND_DRIVER: 282 /* keep track of number of devices in use per hwblk */ 283 hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_DEVICES); 284 break; 285 case BUS_NOTIFY_UNBOUND_DRIVER: 286 /* keep track of number of devices in use per hwblk */ 287 hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_DEVICES); 288 /* make sure driver re-inits itself once */ 289 __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); 290 break; 291 case BUS_NOTIFY_DEL_DEVICE: 292 break; 293 } 294 return 0; 295} 296 297static struct notifier_block platform_bus_notifier = { 298 .notifier_call = platform_bus_notify 299}; 300 301static int __init sh_pm_runtime_init(void) 302{ 303 INIT_WORK(&hwblk_work, platform_pm_runtime_work); 304 305 bus_register_notifier(&platform_bus_type, &platform_bus_notifier); 306 return 0; 307} 308core_initcall(sh_pm_runtime_init); 309