pwm: sysfs: Add suspend/resume support
According to the Documentation/pwm.txt, all PWM consumers should have power management. Since this sysfs interface is one of consumers so that this patch adds suspend/resume support. Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Simon Horman <horms+renesas@verge.net.au> [thierry.reding@gmail.com: fix build warnings for !PM] Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
Родитель
321a7cea97
Коммит
7fd4edc57b
|
@ -27,6 +27,7 @@ struct pwm_export {
|
|||
struct device child;
|
||||
struct pwm_device *pwm;
|
||||
struct mutex lock;
|
||||
struct pwm_state suspend;
|
||||
};
|
||||
|
||||
static struct pwm_export *child_to_pwm_export(struct device *child)
|
||||
|
@ -381,10 +382,111 @@ static struct attribute *pwm_chip_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(pwm_chip);
|
||||
|
||||
/* takes export->lock on success */
|
||||
static struct pwm_export *pwm_class_get_state(struct device *parent,
|
||||
struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct device *child;
|
||||
struct pwm_export *export;
|
||||
|
||||
if (!test_bit(PWMF_EXPORTED, &pwm->flags))
|
||||
return NULL;
|
||||
|
||||
child = device_find_child(parent, pwm, pwm_unexport_match);
|
||||
if (!child)
|
||||
return NULL;
|
||||
|
||||
export = child_to_pwm_export(child);
|
||||
put_device(child); /* for device_find_child() */
|
||||
|
||||
mutex_lock(&export->lock);
|
||||
pwm_get_state(pwm, state);
|
||||
|
||||
return export;
|
||||
}
|
||||
|
||||
static int pwm_class_apply_state(struct pwm_export *export,
|
||||
struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
int ret = pwm_apply_state(pwm, state);
|
||||
|
||||
/* release lock taken in pwm_class_get_state */
|
||||
mutex_unlock(&export->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pwm_class_resume_npwm(struct device *parent, unsigned int npwm)
|
||||
{
|
||||
struct pwm_chip *chip = dev_get_drvdata(parent);
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
struct pwm_state state;
|
||||
struct pwm_export *export;
|
||||
|
||||
export = pwm_class_get_state(parent, pwm, &state);
|
||||
if (!export)
|
||||
continue;
|
||||
|
||||
state.enabled = export->suspend.enabled;
|
||||
ret = pwm_class_apply_state(export, pwm, &state);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused pwm_class_suspend(struct device *parent)
|
||||
{
|
||||
struct pwm_chip *chip = dev_get_drvdata(parent);
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
struct pwm_state state;
|
||||
struct pwm_export *export;
|
||||
|
||||
export = pwm_class_get_state(parent, pwm, &state);
|
||||
if (!export)
|
||||
continue;
|
||||
|
||||
export->suspend = state;
|
||||
state.enabled = false;
|
||||
ret = pwm_class_apply_state(export, pwm, &state);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* roll back the PWM devices that were disabled by
|
||||
* this suspend function.
|
||||
*/
|
||||
pwm_class_resume_npwm(parent, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused pwm_class_resume(struct device *parent)
|
||||
{
|
||||
struct pwm_chip *chip = dev_get_drvdata(parent);
|
||||
|
||||
return pwm_class_resume_npwm(parent, chip->npwm);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pwm_class_pm_ops, pwm_class_suspend, pwm_class_resume);
|
||||
|
||||
static struct class pwm_class = {
|
||||
.name = "pwm",
|
||||
.owner = THIS_MODULE,
|
||||
.dev_groups = pwm_chip_groups,
|
||||
.pm = &pwm_class_pm_ops,
|
||||
};
|
||||
|
||||
static int pwmchip_sysfs_match(struct device *parent, const void *data)
|
||||
|
|
Загрузка…
Ссылка в новой задаче