···4444 int nr_hwblks;4545};46464747+#if !defined(CONFIG_CPU_SUBTYPE_SH7722) && \4848+ !defined(CONFIG_CPU_SUBTYPE_SH7723) && \4949+ !defined(CONFIG_CPU_SUBTYPE_SH7724)4750/* Should be defined by processor-specific code */4851int arch_hwblk_init(void);4952int arch_hwblk_sleep_mode(void);···6966}70677168int sh_hwblk_clk_register(struct clk *clks, int nr);7272-6969+#else7070+#define hwblk_init() 07171+#endif7372#endif /* __ASM_SH_HWBLK_H */
···11-/*22- * arch/sh/kernel/cpu/shmobile/pm_runtime.c33- *44- * Runtime PM support code for SuperH Mobile55- *66- * Copyright (C) 2009 Magnus Damm77- *88- * This file is subject to the terms and conditions of the GNU General Public99- * License. See the file "COPYING" in the main directory of this archive1010- * for more details.1111- */1212-#include <linux/init.h>1313-#include <linux/kernel.h>1414-#include <linux/io.h>1515-#include <linux/pm_runtime.h>1616-#include <linux/platform_device.h>1717-#include <linux/mutex.h>1818-#include <asm/hwblk.h>1919-2020-static DEFINE_SPINLOCK(hwblk_lock);2121-static LIST_HEAD(hwblk_idle_list);2222-static struct work_struct hwblk_work;2323-2424-extern struct hwblk_info *hwblk_info;2525-2626-static void platform_pm_runtime_not_idle(struct platform_device *pdev)2727-{2828- unsigned long flags;2929-3030- /* remove device from idle list */3131- spin_lock_irqsave(&hwblk_lock, flags);3232- if (test_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags)) {3333- list_del(&pdev->archdata.entry);3434- __clear_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags);3535- }3636- spin_unlock_irqrestore(&hwblk_lock, flags);3737-}3838-3939-static int __platform_pm_runtime_resume(struct platform_device *pdev)4040-{4141- struct device *d = &pdev->dev;4242- struct pdev_archdata *ad = &pdev->archdata;4343- int hwblk = ad->hwblk_id;4444- int ret = -ENOSYS;4545-4646- dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk);4747-4848- if (d->driver) {4949- hwblk_enable(hwblk_info, hwblk);5050- ret = 0;5151-5252- if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) {5353- if (d->driver->pm && d->driver->pm->runtime_resume)5454- ret = d->driver->pm->runtime_resume(d);5555-5656- if (!ret)5757- clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);5858- else5959- hwblk_disable(hwblk_info, hwblk);6060- }6161- }6262-6363- dev_dbg(d, "__platform_pm_runtime_resume() [%d] - returns %d\n",6464- hwblk, ret);6565-6666- return ret;6767-}6868-6969-static int __platform_pm_runtime_suspend(struct platform_device *pdev)7070-{7171- struct device *d = &pdev->dev;7272- struct pdev_archdata *ad = &pdev->archdata;7373- int hwblk = ad->hwblk_id;7474- int ret = -ENOSYS;7575-7676- dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk);7777-7878- if (d->driver) {7979- BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags));8080- ret = 0;8181-8282- if (d->driver->pm && d->driver->pm->runtime_suspend) {8383- hwblk_enable(hwblk_info, hwblk);8484- ret = d->driver->pm->runtime_suspend(d);8585- hwblk_disable(hwblk_info, hwblk);8686- }8787-8888- if (!ret) {8989- set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);9090- platform_pm_runtime_not_idle(pdev);9191- hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE);9292- }9393- }9494-9595- dev_dbg(d, "__platform_pm_runtime_suspend() [%d] - returns %d\n",9696- hwblk, ret);9797-9898- return ret;9999-}100100-101101-static void platform_pm_runtime_work(struct work_struct *work)102102-{103103- struct platform_device *pdev;104104- unsigned long flags;105105- int ret;106106-107107- /* go through the idle list and suspend one device at a time */108108- do {109109- spin_lock_irqsave(&hwblk_lock, flags);110110- if (list_empty(&hwblk_idle_list))111111- pdev = NULL;112112- else113113- pdev = list_first_entry(&hwblk_idle_list,114114- struct platform_device,115115- archdata.entry);116116- spin_unlock_irqrestore(&hwblk_lock, flags);117117-118118- if (pdev) {119119- mutex_lock(&pdev->archdata.mutex);120120- ret = __platform_pm_runtime_suspend(pdev);121121-122122- /* at this point the platform device may be:123123- * suspended: ret = 0, FLAG_SUSP set, clock stopped124124- * failed: ret < 0, FLAG_IDLE set, clock stopped125125- */126126- mutex_unlock(&pdev->archdata.mutex);127127- } else {128128- ret = -ENODEV;129129- }130130- } while (!ret);131131-}132132-133133-/* this function gets called from cpuidle context when all devices in the134134- * main power domain are unused but some are counted as idle, ie the hwblk135135- * counter values are (HWBLK_CNT_USAGE == 0) && (HWBLK_CNT_IDLE != 0)136136- */137137-void platform_pm_runtime_suspend_idle(void)138138-{139139- queue_work(pm_wq, &hwblk_work);140140-}141141-142142-static int default_platform_runtime_suspend(struct device *dev)143143-{144144- struct platform_device *pdev = to_platform_device(dev);145145- struct pdev_archdata *ad = &pdev->archdata;146146- unsigned long flags;147147- int hwblk = ad->hwblk_id;148148- int ret = 0;149149-150150- dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);151151-152152- /* ignore off-chip platform devices */153153- if (!hwblk)154154- goto out;155155-156156- /* interrupt context not allowed */157157- might_sleep();158158-159159- /* catch misconfigured drivers not starting with resume */160160- if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &ad->flags)) {161161- ret = -EINVAL;162162- goto out;163163- }164164-165165- /* serialize */166166- mutex_lock(&ad->mutex);167167-168168- /* disable clock */169169- hwblk_disable(hwblk_info, hwblk);170170-171171- /* put device on idle list */172172- spin_lock_irqsave(&hwblk_lock, flags);173173- list_add_tail(&ad->entry, &hwblk_idle_list);174174- __set_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags);175175- spin_unlock_irqrestore(&hwblk_lock, flags);176176-177177- /* increase idle count */178178- hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_IDLE);179179-180180- /* at this point the platform device is:181181- * idle: ret = 0, FLAG_IDLE set, clock stopped182182- */183183- mutex_unlock(&ad->mutex);184184-185185-out:186186- dev_dbg(dev, "%s() [%d] returns %d\n",187187- __func__, hwblk, ret);188188-189189- return ret;190190-}191191-192192-static int default_platform_runtime_resume(struct device *dev)193193-{194194- struct platform_device *pdev = to_platform_device(dev);195195- struct pdev_archdata *ad = &pdev->archdata;196196- int hwblk = ad->hwblk_id;197197- int ret = 0;198198-199199- dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);200200-201201- /* ignore off-chip platform devices */202202- if (!hwblk)203203- goto out;204204-205205- /* interrupt context not allowed */206206- might_sleep();207207-208208- /* serialize */209209- mutex_lock(&ad->mutex);210210-211211- /* make sure device is removed from idle list */212212- platform_pm_runtime_not_idle(pdev);213213-214214- /* decrease idle count */215215- if (!test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags) &&216216- !test_bit(PDEV_ARCHDATA_FLAG_SUSP, &pdev->archdata.flags))217217- hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE);218218-219219- /* resume the device if needed */220220- ret = __platform_pm_runtime_resume(pdev);221221-222222- /* the driver has been initialized now, so clear the init flag */223223- clear_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);224224-225225- /* at this point the platform device may be:226226- * resumed: ret = 0, flags = 0, clock started227227- * failed: ret < 0, FLAG_SUSP set, clock stopped228228- */229229- mutex_unlock(&ad->mutex);230230-out:231231- dev_dbg(dev, "%s() [%d] returns %d\n",232232- __func__, hwblk, ret);233233-234234- return ret;235235-}236236-237237-static int default_platform_runtime_idle(struct device *dev)238238-{239239- struct platform_device *pdev = to_platform_device(dev);240240- int hwblk = pdev->archdata.hwblk_id;241241- int ret = 0;242242-243243- dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);244244-245245- /* ignore off-chip platform devices */246246- if (!hwblk)247247- goto out;248248-249249- /* interrupt context not allowed, use pm_runtime_put()! */250250- might_sleep();251251-252252- /* suspend synchronously to disable clocks immediately */253253- ret = pm_runtime_suspend(dev);254254-out:255255- dev_dbg(dev, "%s() [%d] done!\n", __func__, hwblk);256256- return ret;257257-}258258-259259-static struct dev_pm_domain default_pm_domain = {260260- .ops = {261261- .runtime_suspend = default_platform_runtime_suspend,262262- .runtime_resume = default_platform_runtime_resume,263263- .runtime_idle = default_platform_runtime_idle,264264- USE_PLATFORM_PM_SLEEP_OPS265265- },266266-};267267-268268-static int platform_bus_notify(struct notifier_block *nb,269269- unsigned long action, void *data)270270-{271271- struct device *dev = data;272272- struct platform_device *pdev = to_platform_device(dev);273273- int hwblk = pdev->archdata.hwblk_id;274274-275275- /* ignore off-chip platform devices */276276- if (!hwblk)277277- return 0;278278-279279- switch (action) {280280- case BUS_NOTIFY_ADD_DEVICE:281281- INIT_LIST_HEAD(&pdev->archdata.entry);282282- mutex_init(&pdev->archdata.mutex);283283- /* platform devices without drivers should be disabled */284284- hwblk_enable(hwblk_info, hwblk);285285- hwblk_disable(hwblk_info, hwblk);286286- /* make sure driver re-inits itself once */287287- __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);288288- dev->pm_domain = &default_pm_domain;289289- break;290290- /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */291291- case BUS_NOTIFY_BOUND_DRIVER:292292- /* keep track of number of devices in use per hwblk */293293- hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_DEVICES);294294- break;295295- case BUS_NOTIFY_UNBOUND_DRIVER:296296- /* keep track of number of devices in use per hwblk */297297- hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_DEVICES);298298- /* make sure driver re-inits itself once */299299- __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);300300- break;301301- case BUS_NOTIFY_DEL_DEVICE:302302- dev->pm_domain = NULL;303303- break;304304- }305305- return 0;306306-}307307-308308-static struct notifier_block platform_bus_notifier = {309309- .notifier_call = platform_bus_notify310310-};311311-312312-static int __init sh_pm_runtime_init(void)313313-{314314- INIT_WORK(&hwblk_work, platform_pm_runtime_work);315315-316316- bus_register_notifier(&platform_bus_type, &platform_bus_notifier);317317- return 0;318318-}319319-core_initcall(sh_pm_runtime_init);
+1-8
drivers/sh/Makefile
···77obj-$(CONFIG_MAPLE) += maple/88obj-$(CONFIG_SUPERHYWAY) += superhyway/99obj-$(CONFIG_GENERIC_GPIO) += pfc.o1010-1111-#1212-# For the moment we only use this framework for ARM-based SH/R-Mobile1313-# platforms and generic SH. SH-based SH-Mobile platforms are still using1414-# an older framework that is pending up-porting, at which point this1515-# special casing can go away.1616-#1717-obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE) += pm_runtime.o1010+obj-y += pm_runtime.o