support pm runtime base function

Signed-off-by: dulibo1 <dulibo1@xiaomi.com>
This commit is contained in:
dulibo1 2023-06-25 10:35:11 +08:00 committed by Xiang Xiao
parent 3c96621e1e
commit ac62a08ac9
4 changed files with 421 additions and 0 deletions

View file

@ -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---

View file

@ -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)

View 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);
}

View 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 */