support pm runtime base function
Signed-off-by: dulibo1 <dulibo1@xiaomi.com>
This commit is contained in:
parent
3c96621e1e
commit
ac62a08ac9
4 changed files with 421 additions and 0 deletions
|
@ -29,6 +29,16 @@ config PM_PROCFS
|
|||
---help---
|
||||
Enable procfs for pm.
|
||||
|
||||
config PM_RUNTIME
|
||||
bool "PM runtime support"
|
||||
default n
|
||||
---help---
|
||||
Enable PM runtime that can suspend/resume device by driver
|
||||
when system is running. If the device is not used, you can use
|
||||
PM rutime interface to suspend the device. When the device is
|
||||
needed again, the driver can call the framework to wake up
|
||||
the device.
|
||||
|
||||
config PM_GOVERNOR_GREEDY
|
||||
bool "Greedy governor"
|
||||
---help---
|
||||
|
|
|
@ -31,6 +31,12 @@ CSRCS += pm_procfs.c
|
|||
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PM_RUNTIME),y)
|
||||
|
||||
CSRCS += pm_runtime.c
|
||||
|
||||
endif
|
||||
|
||||
# Governor implementations
|
||||
|
||||
ifeq ($(CONFIG_PM_GOVERNOR_ACTIVITY),y)
|
||||
|
|
326
drivers/power/pm/pm_runtime.c
Normal file
326
drivers/power/pm/pm_runtime.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/****************************************************************************
|
||||
* drivers/power/pm/pm_runtime.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/power/pm_runtime.h>
|
||||
|
||||
#include "pm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int rpm_changestate(FAR struct pm_runtime_s *rpm, rpm_state_e state);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int rpm_suspend(FAR struct pm_runtime_s *rpm)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (rpm->ops && rpm->ops->runtime_suspend)
|
||||
{
|
||||
ret = rpm->ops->runtime_suspend(rpm);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rpm_resume(FAR struct pm_runtime_s *rpm)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (rpm->ops && rpm->ops->runtime_resume)
|
||||
{
|
||||
ret = rpm->ops->runtime_resume(rpm);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rpm_autosuspend_cb(FAR void *arg)
|
||||
{
|
||||
FAR struct pm_runtime_s *rpm = arg;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = pm_lock(&rpm->lock);
|
||||
|
||||
if (rpm->state != RPM_SUSPENDING || !work_available(&rpm->suspend_work))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rpm_changestate(rpm, RPM_SUSPENDED) < 0)
|
||||
{
|
||||
pwrerr("%p runtime suspend failed\n", rpm);
|
||||
rpm->state = RPM_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rpm->state = RPM_SUSPENDED;
|
||||
}
|
||||
|
||||
out:
|
||||
pm_unlock(&rpm->lock, flags);
|
||||
}
|
||||
|
||||
static int rpm_changestate(FAR struct pm_runtime_s *rpm, rpm_state_e state)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (rpm->state)
|
||||
{
|
||||
case RPM_ACTIVE:
|
||||
if (state == RPM_SUSPENDED)
|
||||
{
|
||||
ret = rpm_suspend(rpm);
|
||||
}
|
||||
else if (state == RPM_SUSPENDING)
|
||||
{
|
||||
ret = work_queue(HPWORK, &rpm->suspend_work,
|
||||
rpm_autosuspend_cb, rpm,
|
||||
MSEC2TICK(rpm->suspend_delay));
|
||||
}
|
||||
break;
|
||||
|
||||
case RPM_SUSPENDED:
|
||||
if (state == RPM_ACTIVE)
|
||||
{
|
||||
ret = rpm_resume(rpm);
|
||||
}
|
||||
break;
|
||||
|
||||
case RPM_SUSPENDING:
|
||||
if (state == RPM_ACTIVE)
|
||||
{
|
||||
work_cancel(HPWORK, &rpm->suspend_work);
|
||||
}
|
||||
else if (state == RPM_SUSPENDED)
|
||||
{
|
||||
ret = rpm_suspend(rpm);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pm_runtime_init
|
||||
*
|
||||
* Description:
|
||||
* init struct pm_runtime_s members
|
||||
*
|
||||
* Input Parameters:
|
||||
* rpm - the struct pm_runtime_s addr
|
||||
* state - the init state of the rpm
|
||||
* ops - the struct pm_runtime_ops_s addr
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
****************************************************************************/
|
||||
|
||||
void pm_runtime_init(FAR struct pm_runtime_s *rpm, rpm_state_e state,
|
||||
FAR struct pm_runtime_ops_s *ops)
|
||||
{
|
||||
DEBUGASSERT(rpm != NULL && ops != NULL);
|
||||
DEBUGASSERT(state == RPM_ACTIVE || state == RPM_SUSPENDED);
|
||||
nxrmutex_init(&rpm->lock);
|
||||
rpm->use_count = 0;
|
||||
rpm->suspend_delay = 0;
|
||||
rpm->state = state;
|
||||
rpm->ops = ops;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pm_runtime_get
|
||||
*
|
||||
* Description:
|
||||
* add the rpm use_count, if the first time resume
|
||||
*
|
||||
* Input Parameters:
|
||||
* rpm - the struct pm_runtime_s addr
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success or a negated errno value on failure
|
||||
****************************************************************************/
|
||||
|
||||
int pm_runtime_get(FAR struct pm_runtime_s *rpm)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int ret = 0;
|
||||
|
||||
DEBUGASSERT(rpm != NULL);
|
||||
flags = pm_lock(&rpm->lock);
|
||||
|
||||
if (rpm->use_count++ > 0)
|
||||
{
|
||||
DEBUGASSERT(rpm->state == RPM_ACTIVE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rpm_changestate(rpm, RPM_ACTIVE);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpm->use_count--;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rpm->state = RPM_ACTIVE;
|
||||
out:
|
||||
pm_unlock(&rpm->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pm_runtime_put
|
||||
*
|
||||
* Description:
|
||||
* drop the rpm use_count, if refcnt is zero suspend
|
||||
*
|
||||
* Input Parameters:
|
||||
* rpm - the struct pm_runtime_s addr
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success or a negated errno value on failure
|
||||
****************************************************************************/
|
||||
|
||||
int pm_runtime_put(FAR struct pm_runtime_s *rpm)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int ret = 0;
|
||||
|
||||
DEBUGASSERT(rpm != NULL);
|
||||
flags = pm_lock(&rpm->lock);
|
||||
if (rpm->use_count == 0)
|
||||
{
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(rpm->state == RPM_ACTIVE);
|
||||
if (--rpm->use_count > 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rpm_changestate(rpm, RPM_SUSPENDED);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpm->use_count++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rpm->state = RPM_SUSPENDED;
|
||||
out:
|
||||
pm_unlock(&rpm->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pm_runtime_put_autosuspend
|
||||
*
|
||||
* Description:
|
||||
* drop the rpm use_count, if refcnt is zero suspend or suspend
|
||||
* (depends suspend_delay) after a delay duration
|
||||
*
|
||||
* Input Parameters:
|
||||
* rpm - the struct pm_runtime_s addr
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success or a negated errno value on failure
|
||||
****************************************************************************/
|
||||
|
||||
int pm_runtime_put_autosuspend(FAR struct pm_runtime_s *rpm)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int ret = 0;
|
||||
|
||||
DEBUGASSERT(rpm != NULL);
|
||||
flags = pm_lock(&rpm->lock);
|
||||
if (rpm->use_count == 0)
|
||||
{
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(rpm->state == RPM_ACTIVE);
|
||||
if (--rpm->use_count > 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rpm_changestate(rpm, RPM_SUSPENDING);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpm->use_count++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rpm->state = RPM_SUSPENDING;
|
||||
out:
|
||||
pm_unlock(&rpm->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pm_runtime_set_autosuspend_delay
|
||||
*
|
||||
* Description:
|
||||
* set rpm autosuspend_delay
|
||||
*
|
||||
* Input Parameters:
|
||||
* rpm - the struct pm_runtime_s addr
|
||||
* delay - the delay in milliseconds
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
****************************************************************************/
|
||||
|
||||
void pm_runtime_set_autosuspend_delay(FAR struct pm_runtime_s *rpm,
|
||||
unsigned int delay)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
DEBUGASSERT(rpm != NULL);
|
||||
flags = pm_lock(&rpm->lock);
|
||||
rpm->suspend_delay = delay;
|
||||
pm_unlock(&rpm->lock, flags);
|
||||
}
|
79
include/nuttx/power/pm_runtime.h
Normal file
79
include/nuttx/power/pm_runtime.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/power/pm_runtime.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_POWER_PM_RUNTIME_H
|
||||
#define __INCLUDE_NUTTX_POWER_PM_RUNTIME_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/mutex.h>
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RPM_ACTIVE = 0,
|
||||
RPM_SUSPENDED,
|
||||
RPM_SUSPENDING,
|
||||
} rpm_state_e;
|
||||
|
||||
struct pm_runtime_ops_s;
|
||||
struct pm_runtime_s
|
||||
{
|
||||
rmutex_t lock;
|
||||
unsigned int use_count;
|
||||
rpm_state_e state;
|
||||
unsigned int suspend_delay;
|
||||
struct work_s suspend_work;
|
||||
FAR const struct pm_runtime_ops_s *ops;
|
||||
};
|
||||
|
||||
struct pm_runtime_ops_s
|
||||
{
|
||||
CODE int (*runtime_suspend)(FAR struct pm_runtime_s *rpm);
|
||||
CODE int (*runtime_resume)(FAR struct pm_runtime_s *rpm);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
void pm_runtime_init(FAR struct pm_runtime_s *rpm, rpm_state_e state,
|
||||
FAR struct pm_runtime_ops_s *rops);
|
||||
int pm_runtime_get(FAR struct pm_runtime_s *rpm);
|
||||
int pm_runtime_put(FAR struct pm_runtime_s *rpm);
|
||||
int pm_runtime_put_autosuspend(FAR struct pm_runtime_s *rpm);
|
||||
void pm_runtime_set_autosuspend_delay(FAR struct pm_runtime_s *rpm,
|
||||
unsigned int delay);
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
#endif /* __INCLUDE_NUTTX_POWER_PM_RUNTIME_H */
|
Loading…
Reference in a new issue