From 18fc64dcffbe30c5cddfbe5cabcd30f50adf9ea3 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 8 Apr 2016 22:15:15 -0700 Subject: [PATCH] power_mgmt: Sample usage of device_xxx__busy() APIs To show possible usage of the device_busy_xxx() APIs. Meant to show how drivers and power policy manager can use them. Change-Id: I49d1dedd9a7b8d6bf09080c6c7243f0666330941 Signed-off-by: Jithu Joseph --- drivers/i2c/i2c_dw.c | 16 ++++++++++++++++ samples/power/power_mgr/prj.conf | 1 + samples/power/power_mgr/src/main.c | 16 +++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index 62819fd3a68..b5d0b46c643 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -459,6 +459,20 @@ static int i2c_dw_transfer(struct device *dev, /* Enable controller */ regs->ic_enable.bits.enable = 1; + /* + * While waiting at device_sync_call_wait(), kernel can switch to idle + * task which in turn can call _sys_soc_suspend() hook of Power + * Management App (PMA). + * device_busy_set() call here, would indicate to PMA that it should not + * execute PM policies that would turn off this ip block, causing an + * ongoing hw transaction to be left in an inconsistent state. + * Note : This is just a sample to show a possible use of the API, it is + * upto the driver expert to see, if he actually needs it here, or + * somewhere else, or not needed as the driver's suspend()/resume() + * can handle everything + */ + device_busy_set(dev); + /* Process all the messages */ while (msg_left > 0) { pflags = dw->xfr_flags; @@ -517,6 +531,8 @@ static int i2c_dw_transfer(struct device *dev, msg_left--; } + device_busy_clear(dev); + dw->state = I2C_DW_STATE_READY; return ret; diff --git a/samples/power/power_mgr/prj.conf b/samples/power/power_mgr/prj.conf index 1bdf85055e5..57a240cef5b 100644 --- a/samples/power/power_mgr/prj.conf +++ b/samples/power/power_mgr/prj.conf @@ -5,3 +5,4 @@ CONFIG_TICKLESS_IDLE=y CONFIG_RTC=y CONFIG_GPIO=y CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y \ No newline at end of file diff --git a/samples/power/power_mgr/src/main.c b/samples/power/power_mgr/src/main.c index c0c774ffb24..687dc256e8e 100644 --- a/samples/power/power_mgr/src/main.c +++ b/samples/power/power_mgr/src/main.c @@ -79,9 +79,10 @@ static int check_pm_policy(int32_t ticks) * 0 = no power saving operation * 1 = low power state * 2 = device suspend only + * 3 = deep sleep * */ - policy = (policy > 2 ? 0 : policy); + policy = (policy > 3 ? 0 : policy); return policy++; } @@ -123,6 +124,15 @@ int _sys_soc_suspend(int32_t ticks) start_time = rtc_read(rtc_dev); ret = device_suspend_only_entry(ticks); break; + case 3: + /* + * if the policy manager chooses to go to deep sleep, we need to + * check if any device is in the middle of a transaction + */ + if (!device_any_busy_check()) { + /* Do deep sleep operations */ + /* break; (fall through for now) */ + } default: /* No PM operations */ ret = SYS_PM_NOT_HANDLED; @@ -190,6 +200,10 @@ static void suspend_devices(int pm_policy) for (i = 0; i < device_count; i++) { int idx = device_policy_list[i]; + /* If necessary the policy manager can check if a specific + * device in the policy list is busy as shown below : + * if(device_busy_check(&device_list[idx])) {do something} + */ device_retval[i] = device_suspend(&device_list[idx], pm_policy); } }