diff options
Diffstat (limited to 'arch/sh/kernel/cpu/shmobile/pm_runtime.c')
| -rw-r--r-- | arch/sh/kernel/cpu/shmobile/pm_runtime.c | 308 | 
1 files changed, 0 insertions, 308 deletions
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c deleted file mode 100644 index 6dcb8166a64..00000000000 --- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * arch/sh/kernel/cpu/shmobile/pm_runtime.c - * - * Runtime PM support code for SuperH Mobile - * - *  Copyright (C) 2009 Magnus Damm - * - * This file is subject to the terms and conditions of the GNU General Public - * License.  See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/io.h> -#include <linux/pm_runtime.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <asm/hwblk.h> - -static DEFINE_SPINLOCK(hwblk_lock); -static LIST_HEAD(hwblk_idle_list); -static struct work_struct hwblk_work; - -extern struct hwblk_info *hwblk_info; - -static void platform_pm_runtime_not_idle(struct platform_device *pdev) -{ -	unsigned long flags; - -	/* remove device from idle list */ -	spin_lock_irqsave(&hwblk_lock, flags); -	if (test_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags)) { -		list_del(&pdev->archdata.entry); -		__clear_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags); -	} -	spin_unlock_irqrestore(&hwblk_lock, flags); -} - -static int __platform_pm_runtime_resume(struct platform_device *pdev) -{ -	struct device *d = &pdev->dev; -	struct pdev_archdata *ad = &pdev->archdata; -	int hwblk = ad->hwblk_id; -	int ret = -ENOSYS; - -	dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk); - -	if (d->driver) { -		hwblk_enable(hwblk_info, hwblk); -		ret = 0; - -		if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) { -			if (d->driver->pm && d->driver->pm->runtime_resume) -				ret = d->driver->pm->runtime_resume(d); - -			if (!ret) -				clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); -			else -				hwblk_disable(hwblk_info, hwblk); -		} -	} - -	dev_dbg(d, "__platform_pm_runtime_resume() [%d] - returns %d\n", -		hwblk, ret); - -	return ret; -} - -static int __platform_pm_runtime_suspend(struct platform_device *pdev) -{ -	struct device *d = &pdev->dev; -	struct pdev_archdata *ad = &pdev->archdata; -	int hwblk = ad->hwblk_id; -	int ret = -ENOSYS; - -	dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk); - -	if (d->driver) { -		BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags)); -		ret = 0; - -		if (d->driver->pm && d->driver->pm->runtime_suspend) { -			hwblk_enable(hwblk_info, hwblk); -			ret = d->driver->pm->runtime_suspend(d); -			hwblk_disable(hwblk_info, hwblk); -		} - -		if (!ret) { -			set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); -			platform_pm_runtime_not_idle(pdev); -			hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE); -		} -	} - -	dev_dbg(d, "__platform_pm_runtime_suspend() [%d] - returns %d\n", -		hwblk, ret); - -	return ret; -} - -static void platform_pm_runtime_work(struct work_struct *work) -{ -	struct platform_device *pdev; -	unsigned long flags; -	int ret; - -	/* go through the idle list and suspend one device at a time */ -	do { -		spin_lock_irqsave(&hwblk_lock, flags); -		if (list_empty(&hwblk_idle_list)) -			pdev = NULL; -		else -			pdev = list_first_entry(&hwblk_idle_list, -						struct platform_device, -						archdata.entry); -		spin_unlock_irqrestore(&hwblk_lock, flags); - -		if (pdev) { -			mutex_lock(&pdev->archdata.mutex); -			ret = __platform_pm_runtime_suspend(pdev); - -			/* at this point the platform device may be: -			 * suspended: ret = 0, FLAG_SUSP set, clock stopped -			 * failed: ret < 0, FLAG_IDLE set, clock stopped -			 */ -			mutex_unlock(&pdev->archdata.mutex); -		} else { -			ret = -ENODEV; -		} -	} while (!ret); -} - -/* this function gets called from cpuidle context when all devices in the - * main power domain are unused but some are counted as idle, ie the hwblk - * counter values are (HWBLK_CNT_USAGE == 0) && (HWBLK_CNT_IDLE != 0) - */ -void platform_pm_runtime_suspend_idle(void) -{ -	queue_work(pm_wq, &hwblk_work); -} - -int platform_pm_runtime_suspend(struct device *dev) -{ -	struct platform_device *pdev = to_platform_device(dev); -	struct pdev_archdata *ad = &pdev->archdata; -	unsigned long flags; -	int hwblk = ad->hwblk_id; -	int ret = 0; - -	dev_dbg(dev, "platform_pm_runtime_suspend() [%d]\n", hwblk); - -	/* ignore off-chip platform devices */ -	if (!hwblk) -		goto out; - -	/* interrupt context not allowed */ -	might_sleep(); - -	/* catch misconfigured drivers not starting with resume */ -	if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags)) { -		ret = -EINVAL; -		goto out; -	} - -	/* serialize */ -	mutex_lock(&ad->mutex); - -	/* disable clock */ -	hwblk_disable(hwblk_info, hwblk); - -	/* put device on idle list */ -	spin_lock_irqsave(&hwblk_lock, flags); -	list_add_tail(&pdev->archdata.entry, &hwblk_idle_list); -	__set_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags); -	spin_unlock_irqrestore(&hwblk_lock, flags); - -	/* increase idle count */ -	hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_IDLE); - -	/* at this point the platform device is: -	 * idle: ret = 0, FLAG_IDLE set, clock stopped -	 */ -	mutex_unlock(&ad->mutex); - -out: -	dev_dbg(dev, "platform_pm_runtime_suspend() [%d] returns %d\n", -		hwblk, ret); - -	return ret; -} - -int platform_pm_runtime_resume(struct device *dev) -{ -	struct platform_device *pdev = to_platform_device(dev); -	struct pdev_archdata *ad = &pdev->archdata; -	int hwblk = ad->hwblk_id; -	int ret = 0; - -	dev_dbg(dev, "platform_pm_runtime_resume() [%d]\n", hwblk); - -	/* ignore off-chip platform devices */ -	if (!hwblk) -		goto out; - -	/* interrupt context not allowed */ -	might_sleep(); - -	/* serialize */ -	mutex_lock(&ad->mutex); - -	/* make sure device is removed from idle list */ -	platform_pm_runtime_not_idle(pdev); - -	/* decrease idle count */ -	if (!test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags) && -	    !test_bit(PDEV_ARCHDATA_FLAG_SUSP, &pdev->archdata.flags)) -		hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE); - -	/* resume the device if needed */ -	ret = __platform_pm_runtime_resume(pdev); - -	/* the driver has been initialized now, so clear the init flag */ -	clear_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); - -	/* at this point the platform device may be: -	 * resumed: ret = 0, flags = 0, clock started -	 * failed: ret < 0, FLAG_SUSP set, clock stopped -	 */ -	mutex_unlock(&ad->mutex); -out: -	dev_dbg(dev, "platform_pm_runtime_resume() [%d] returns %d\n", -		hwblk, ret); - -	return ret; -} - -int platform_pm_runtime_idle(struct device *dev) -{ -	struct platform_device *pdev = to_platform_device(dev); -	int hwblk = pdev->archdata.hwblk_id; -	int ret = 0; - -	dev_dbg(dev, "platform_pm_runtime_idle() [%d]\n", hwblk); - -	/* ignore off-chip platform devices */ -	if (!hwblk) -		goto out; - -	/* interrupt context not allowed, use pm_runtime_put()! */ -	might_sleep(); - -	/* suspend synchronously to disable clocks immediately */ -	ret = pm_runtime_suspend(dev); -out: -	dev_dbg(dev, "platform_pm_runtime_idle() [%d] done!\n", hwblk); -	return ret; -} - -static int platform_bus_notify(struct notifier_block *nb, -			       unsigned long action, void *data) -{ -	struct device *dev = data; -	struct platform_device *pdev = to_platform_device(dev); -	int hwblk = pdev->archdata.hwblk_id; - -	/* ignore off-chip platform devices */ -	if (!hwblk) -		return 0; - -	switch (action) { -	case BUS_NOTIFY_ADD_DEVICE: -		INIT_LIST_HEAD(&pdev->archdata.entry); -		mutex_init(&pdev->archdata.mutex); -		/* platform devices without drivers should be disabled */ -		hwblk_enable(hwblk_info, hwblk); -		hwblk_disable(hwblk_info, hwblk); -		/* make sure driver re-inits itself once */ -		__set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); -		break; -	/* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */ -	case BUS_NOTIFY_BOUND_DRIVER: -		/* keep track of number of devices in use per hwblk */ -		hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_DEVICES); -		break; -	case BUS_NOTIFY_UNBOUND_DRIVER: -		/* keep track of number of devices in use per hwblk */ -		hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_DEVICES); -		/* make sure driver re-inits itself once */ -		__set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); -		break; -	case BUS_NOTIFY_DEL_DEVICE: -		break; -	} -	return 0; -} - -static struct notifier_block platform_bus_notifier = { -	.notifier_call = platform_bus_notify -}; - -static int __init sh_pm_runtime_init(void) -{ -	INIT_WORK(&hwblk_work, platform_pm_runtime_work); - -	bus_register_notifier(&platform_bus_type, &platform_bus_notifier); -	return 0; -} -core_initcall(sh_pm_runtime_init);  | 
