Merge branches 'sh/hwblk' and 'sh/pm-runtime'
This commit is contained in:
@@ -164,11 +164,11 @@ static struct clk mstp_clks[] = {
|
||||
SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
|
||||
SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
|
||||
SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
|
||||
SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, 0),
|
||||
SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
|
||||
SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
|
||||
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU, 0),
|
||||
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, 0),
|
||||
SH_HWBLK_CLK("lcdc0", -1, P_CLK, HWBLK_LCDC, 0),
|
||||
};
|
||||
|
||||
|
@@ -190,12 +190,12 @@ static struct clk mstp_clks[] = {
|
||||
SH_HWBLK_CLK("usb0", -1, B_CLK, HWBLK_USB, 0),
|
||||
SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
|
||||
SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0),
|
||||
SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU2H1, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU2H1, 0),
|
||||
SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
|
||||
SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0),
|
||||
SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0),
|
||||
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU2H0, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU2H0, 0),
|
||||
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, 0),
|
||||
SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0),
|
||||
};
|
||||
|
||||
|
@@ -204,17 +204,17 @@ static struct clk mstp_clks[] = {
|
||||
SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0),
|
||||
SH_HWBLK_CLK("sdhi0", -1, B_CLK, HWBLK_SDHI0, 0),
|
||||
SH_HWBLK_CLK("sdhi1", -1, B_CLK, HWBLK_SDHI1, 0),
|
||||
SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU1, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU1, 0),
|
||||
SH_HWBLK_CLK("ceu1", -1, B_CLK, HWBLK_CEU1, 0),
|
||||
SH_HWBLK_CLK("beu1", -1, B_CLK, HWBLK_BEU1, 0),
|
||||
SH_HWBLK_CLK("2ddmac0", -1, SH_CLK, HWBLK_2DDMAC, 0),
|
||||
SH_HWBLK_CLK("spu0", -1, B_CLK, HWBLK_SPU, 0),
|
||||
SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, 0),
|
||||
SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0),
|
||||
SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU0, 0),
|
||||
SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU0, 0),
|
||||
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU0, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT),
|
||||
SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU0, 0),
|
||||
SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, 0),
|
||||
SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0),
|
||||
};
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <linux/sh_timer.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <cpu/sh7722.h>
|
||||
|
||||
static struct resource rtc_resources[] = {
|
||||
[0] = {
|
||||
@@ -46,6 +47,9 @@ static struct platform_device rtc_device = {
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
.resource = rtc_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_RTC,
|
||||
},
|
||||
};
|
||||
|
||||
static struct m66592_platdata usbf_platdata = {
|
||||
@@ -76,6 +80,9 @@ static struct platform_device usbf_device = {
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(usbf_resources),
|
||||
.resource = usbf_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_USBF,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource iic_resources[] = {
|
||||
@@ -97,6 +104,9 @@ static struct platform_device iic_device = {
|
||||
.id = 0, /* "i2c0" clock */
|
||||
.num_resources = ARRAY_SIZE(iic_resources),
|
||||
.resource = iic_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_IIC,
|
||||
},
|
||||
};
|
||||
|
||||
static struct uio_info vpu_platform_data = {
|
||||
@@ -125,6 +135,9 @@ static struct platform_device vpu_device = {
|
||||
},
|
||||
.resource = vpu_resources,
|
||||
.num_resources = ARRAY_SIZE(vpu_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VPU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct uio_info veu_platform_data = {
|
||||
@@ -153,6 +166,9 @@ static struct platform_device veu_device = {
|
||||
},
|
||||
.resource = veu_resources,
|
||||
.num_resources = ARRAY_SIZE(veu_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VEU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct uio_info jpu_platform_data = {
|
||||
@@ -181,6 +197,9 @@ static struct platform_device jpu_device = {
|
||||
},
|
||||
.resource = jpu_resources,
|
||||
.num_resources = ARRAY_SIZE(jpu_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_JPU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config cmt_platform_data = {
|
||||
@@ -213,6 +232,9 @@ static struct platform_device cmt_device = {
|
||||
},
|
||||
.resource = cmt_resources,
|
||||
.num_resources = ARRAY_SIZE(cmt_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_CMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu0_platform_data = {
|
||||
@@ -244,6 +266,9 @@ static struct platform_device tmu0_device = {
|
||||
},
|
||||
.resource = tmu0_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu0_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu1_platform_data = {
|
||||
@@ -275,6 +300,9 @@ static struct platform_device tmu1_device = {
|
||||
},
|
||||
.resource = tmu1_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu1_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu2_platform_data = {
|
||||
@@ -305,6 +333,9 @@ static struct platform_device tmu2_device = {
|
||||
},
|
||||
.resource = tmu2_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu2_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct plat_sci_port sci_platform_data[] = {
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <cpu/sh7723.h>
|
||||
|
||||
static struct uio_info vpu_platform_data = {
|
||||
.name = "VPU5",
|
||||
@@ -45,6 +46,9 @@ static struct platform_device vpu_device = {
|
||||
},
|
||||
.resource = vpu_resources,
|
||||
.num_resources = ARRAY_SIZE(vpu_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VPU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct uio_info veu0_platform_data = {
|
||||
@@ -73,6 +77,9 @@ static struct platform_device veu0_device = {
|
||||
},
|
||||
.resource = veu0_resources,
|
||||
.num_resources = ARRAY_SIZE(veu0_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VEU2H0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct uio_info veu1_platform_data = {
|
||||
@@ -101,6 +108,9 @@ static struct platform_device veu1_device = {
|
||||
},
|
||||
.resource = veu1_resources,
|
||||
.num_resources = ARRAY_SIZE(veu1_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VEU2H1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config cmt_platform_data = {
|
||||
@@ -133,6 +143,9 @@ static struct platform_device cmt_device = {
|
||||
},
|
||||
.resource = cmt_resources,
|
||||
.num_resources = ARRAY_SIZE(cmt_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_CMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu0_platform_data = {
|
||||
@@ -164,6 +177,9 @@ static struct platform_device tmu0_device = {
|
||||
},
|
||||
.resource = tmu0_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu0_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu1_platform_data = {
|
||||
@@ -195,6 +211,9 @@ static struct platform_device tmu1_device = {
|
||||
},
|
||||
.resource = tmu1_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu1_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu2_platform_data = {
|
||||
@@ -225,6 +244,9 @@ static struct platform_device tmu2_device = {
|
||||
},
|
||||
.resource = tmu2_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu2_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu3_platform_data = {
|
||||
@@ -255,6 +277,9 @@ static struct platform_device tmu3_device = {
|
||||
},
|
||||
.resource = tmu3_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu3_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu4_platform_data = {
|
||||
@@ -285,6 +310,9 @@ static struct platform_device tmu4_device = {
|
||||
},
|
||||
.resource = tmu4_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu4_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu5_platform_data = {
|
||||
@@ -315,6 +343,9 @@ static struct platform_device tmu5_device = {
|
||||
},
|
||||
.resource = tmu5_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu5_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct plat_sci_port sci_platform_data[] = {
|
||||
@@ -395,6 +426,9 @@ static struct platform_device rtc_device = {
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
.resource = rtc_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_RTC,
|
||||
},
|
||||
};
|
||||
|
||||
static struct r8a66597_platdata r8a66597_data = {
|
||||
@@ -424,6 +458,9 @@ static struct platform_device sh7723_usb_host_device = {
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(sh7723_usb_host_resources),
|
||||
.resource = sh7723_usb_host_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_USB,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource iic_resources[] = {
|
||||
@@ -445,6 +482,9 @@ static struct platform_device iic_device = {
|
||||
.id = 0, /* "i2c0" clock */
|
||||
.num_resources = ARRAY_SIZE(iic_resources),
|
||||
.resource = iic_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_IIC,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *sh7723_devices[] __initdata = {
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/mmzone.h>
|
||||
#include <cpu/sh7724.h>
|
||||
|
||||
/* Serial */
|
||||
static struct plat_sci_port sci_platform_data[] = {
|
||||
@@ -103,6 +104,9 @@ static struct platform_device rtc_device = {
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
.resource = rtc_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_RTC,
|
||||
},
|
||||
};
|
||||
|
||||
/* I2C0 */
|
||||
@@ -125,6 +129,9 @@ static struct platform_device iic0_device = {
|
||||
.id = 0, /* "i2c0" clock */
|
||||
.num_resources = ARRAY_SIZE(iic0_resources),
|
||||
.resource = iic0_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_IIC0,
|
||||
},
|
||||
};
|
||||
|
||||
/* I2C1 */
|
||||
@@ -147,6 +154,9 @@ static struct platform_device iic1_device = {
|
||||
.id = 1, /* "i2c1" clock */
|
||||
.num_resources = ARRAY_SIZE(iic1_resources),
|
||||
.resource = iic1_resources,
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_IIC1,
|
||||
},
|
||||
};
|
||||
|
||||
/* VPU */
|
||||
@@ -176,6 +186,9 @@ static struct platform_device vpu_device = {
|
||||
},
|
||||
.resource = vpu_resources,
|
||||
.num_resources = ARRAY_SIZE(vpu_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VPU,
|
||||
},
|
||||
};
|
||||
|
||||
/* VEU0 */
|
||||
@@ -205,6 +218,9 @@ static struct platform_device veu0_device = {
|
||||
},
|
||||
.resource = veu0_resources,
|
||||
.num_resources = ARRAY_SIZE(veu0_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VEU0,
|
||||
},
|
||||
};
|
||||
|
||||
/* VEU1 */
|
||||
@@ -234,6 +250,9 @@ static struct platform_device veu1_device = {
|
||||
},
|
||||
.resource = veu1_resources,
|
||||
.num_resources = ARRAY_SIZE(veu1_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_VEU1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config cmt_platform_data = {
|
||||
@@ -266,6 +285,9 @@ static struct platform_device cmt_device = {
|
||||
},
|
||||
.resource = cmt_resources,
|
||||
.num_resources = ARRAY_SIZE(cmt_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_CMT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu0_platform_data = {
|
||||
@@ -297,6 +319,9 @@ static struct platform_device tmu0_device = {
|
||||
},
|
||||
.resource = tmu0_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu0_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu1_platform_data = {
|
||||
@@ -328,6 +353,9 @@ static struct platform_device tmu1_device = {
|
||||
},
|
||||
.resource = tmu1_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu1_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu2_platform_data = {
|
||||
@@ -358,6 +386,9 @@ static struct platform_device tmu2_device = {
|
||||
},
|
||||
.resource = tmu2_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu2_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU0,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -389,6 +420,9 @@ static struct platform_device tmu3_device = {
|
||||
},
|
||||
.resource = tmu3_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu3_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu4_platform_data = {
|
||||
@@ -419,6 +453,9 @@ static struct platform_device tmu4_device = {
|
||||
},
|
||||
.resource = tmu4_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu4_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct sh_timer_config tmu5_platform_data = {
|
||||
@@ -449,6 +486,9 @@ static struct platform_device tmu5_device = {
|
||||
},
|
||||
.resource = tmu5_resources,
|
||||
.num_resources = ARRAY_SIZE(tmu5_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_TMU1,
|
||||
},
|
||||
};
|
||||
|
||||
/* JPU */
|
||||
@@ -478,6 +518,9 @@ static struct platform_device jpu_device = {
|
||||
},
|
||||
.resource = jpu_resources,
|
||||
.num_resources = ARRAY_SIZE(jpu_resources),
|
||||
.archdata = {
|
||||
.hwblk_id = HWBLK_JPU,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *sh7724_devices[] __initdata = {
|
||||
|
@@ -5,3 +5,4 @@
|
||||
# Power Management & Sleep mode
|
||||
obj-$(CONFIG_PM) += pm.o sleep.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_PM_RUNTIME) += pm_runtime.o
|
||||
|
303
arch/sh/kernel/cpu/shmobile/pm_runtime.c
Normal file
303
arch/sh/kernel/cpu/shmobile/pm_runtime.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* 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 && d->driver->pm && d->driver->pm->runtime_resume) {
|
||||
hwblk_enable(hwblk_info, hwblk);
|
||||
ret = 0;
|
||||
|
||||
if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) {
|
||||
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 && d->driver->pm && d->driver->pm->runtime_suspend) {
|
||||
BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags));
|
||||
|
||||
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);
|
Reference in New Issue
Block a user