drivers: led_pwm: Handle power state changes
Suspend/resume PMW device when PWM LEDs are suspended/resumed. Signed-off-by: Pawel Dunaj <pawel.dunaj@nordicsemi.no>
This commit is contained in:
parent
8d348f0076
commit
1caf5fd21e
1 changed files with 96 additions and 4 deletions
|
@ -21,6 +21,7 @@
|
||||||
LOG_MODULE_REGISTER(led_pwm, CONFIG_LED_LOG_LEVEL);
|
LOG_MODULE_REGISTER(led_pwm, CONFIG_LED_LOG_LEVEL);
|
||||||
|
|
||||||
#define DEV_CFG(dev) ((const struct led_pwm_config *) ((dev)->config))
|
#define DEV_CFG(dev) ((const struct led_pwm_config *) ((dev)->config))
|
||||||
|
#define DEV_DATA(dev) ((struct led_pwm_data *) ((dev)->data))
|
||||||
|
|
||||||
struct led_pwm {
|
struct led_pwm {
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
|
@ -34,6 +35,12 @@ struct led_pwm_config {
|
||||||
const struct led_pwm *led;
|
const struct led_pwm *led;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct led_pwm_data {
|
||||||
|
#ifdef CONFIG_PM_DEVICE
|
||||||
|
uint32_t pm_state;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
static int led_pwm_blink(const struct device *dev, uint32_t led,
|
static int led_pwm_blink(const struct device *dev, uint32_t led,
|
||||||
uint32_t delay_on, uint32_t delay_off)
|
uint32_t delay_on, uint32_t delay_off)
|
||||||
{
|
{
|
||||||
|
@ -110,9 +117,92 @@ static int led_pwm_init(const struct device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_DEVICE
|
||||||
|
struct led_pwm_data *data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
data->pm_state = DEVICE_PM_ACTIVE_STATE;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_DEVICE
|
||||||
|
|
||||||
|
static int led_pwm_pm_get_state(const struct device *dev, uint32_t *state)
|
||||||
|
{
|
||||||
|
struct led_pwm_data *data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
unsigned int key = irq_lock();
|
||||||
|
*state = data->pm_state;
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_pwm_pm_set_state(const struct device *dev, uint32_t new_state)
|
||||||
|
{
|
||||||
|
const struct led_pwm_config *config = DEV_CFG(dev);
|
||||||
|
struct led_pwm_data *data = DEV_DATA(dev);
|
||||||
|
uint32_t old_state;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
|
old_state = data->pm_state;
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
if (old_state == new_state) {
|
||||||
|
/* leave unchanged */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* switch all underlying PWM devices to the new state */
|
||||||
|
for (size_t i = 0; i < config->num_leds; i++) {
|
||||||
|
const struct led_pwm *led_pwm = &config->led[i];
|
||||||
|
|
||||||
|
LOG_DBG("Switching PWM %p to state %" PRIu32, led_pwm->dev, new_state);
|
||||||
|
int err = device_set_power_state(led_pwm->dev, new_state, NULL, NULL);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Cannot switch PWM %p power state", led_pwm->dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* record the new state */
|
||||||
|
key = irq_lock();
|
||||||
|
data->pm_state = new_state;
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_pwm_pm_control(const struct device *dev, uint32_t ctrl_command,
|
||||||
|
void *context, device_pm_cb cb, void *arg)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
switch (ctrl_command) {
|
||||||
|
case DEVICE_PM_GET_POWER_STATE:
|
||||||
|
err = led_pwm_pm_get_state(dev, context);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_PM_SET_POWER_STATE:
|
||||||
|
err = led_pwm_pm_set_state(dev, *((uint32_t *)context));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = -ENOTSUP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
cb(dev, err, context, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_PM_DEVICE */
|
||||||
|
|
||||||
static const struct led_driver_api led_pwm_api = {
|
static const struct led_driver_api led_pwm_api = {
|
||||||
.on = led_pwm_on,
|
.on = led_pwm_on,
|
||||||
.off = led_pwm_off,
|
.off = led_pwm_off,
|
||||||
|
@ -131,20 +221,22 @@ static const struct led_driver_api led_pwm_api = {
|
||||||
|
|
||||||
#define LED_PWM_DEVICE(id) \
|
#define LED_PWM_DEVICE(id) \
|
||||||
\
|
\
|
||||||
const struct led_pwm led_pwm_##id[] = { \
|
static const struct led_pwm led_pwm_##id[] = { \
|
||||||
DT_INST_FOREACH_CHILD(id, LED_PWM) \
|
DT_INST_FOREACH_CHILD(id, LED_PWM) \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
const struct led_pwm_config led_pwm_config_##id = { \
|
static const struct led_pwm_config led_pwm_config_##id = { \
|
||||||
.num_leds = ARRAY_SIZE(led_pwm_##id), \
|
.num_leds = ARRAY_SIZE(led_pwm_##id), \
|
||||||
.led = led_pwm_##id, \
|
.led = led_pwm_##id, \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
|
static struct led_pwm_data led_pwm_data_##id; \
|
||||||
|
\
|
||||||
DEVICE_DEFINE(led_pwm_##id, \
|
DEVICE_DEFINE(led_pwm_##id, \
|
||||||
DT_INST_PROP_OR(id, label, "LED_PWM_"#id), \
|
DT_INST_PROP_OR(id, label, "LED_PWM_"#id), \
|
||||||
&led_pwm_init, \
|
&led_pwm_init, \
|
||||||
device_pm_control_nop, \
|
led_pwm_pm_control, \
|
||||||
NULL, \
|
&led_pwm_data_##id, \
|
||||||
&led_pwm_config_##id, \
|
&led_pwm_config_##id, \
|
||||||
POST_KERNEL, CONFIG_LED_INIT_PRIORITY, \
|
POST_KERNEL, CONFIG_LED_INIT_PRIORITY, \
|
||||||
&led_pwm_api);
|
&led_pwm_api);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue