From 88f8bc8e0f1904f754db65d2eb7e60666135e62a Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 20 Oct 2020 15:19:21 +0800 Subject: [PATCH] pwm: rockchip: Support pwm oneshot mode for specified number of cycles. The oneshot_count value should be less than PWM_ONESHOT_COUNT_MAX. If oneshot_count == 0, this pwm channel works in continuous mode. Signed-off-by: Steven Liu Change-Id: I45857fb5762e0365cce5278502479c580638e40c --- drivers/pwm/Kconfig | 6 ++++++ drivers/pwm/pwm-rockchip.c | 26 +++++++++++++++++++++++--- include/linux/pwm.h | 3 +++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 504d252716f2..fd35cd9d852d 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -369,6 +369,12 @@ config PWM_ROCKCHIP Generic PWM framework driver for the PWM controller found on Rockchip SoCs. +config PWM_ROCKCHIP_ONESHOT + bool "Rockchip PWM oneshot mode support" + depends on PWM_ROCKCHIP + help + Support Rockchip pwm oneshot mode for specified number of cycles. + config PWM_SAMSUNG tristate "Samsung PWM support" depends on PLAT_SAMSUNG || ARCH_EXYNOS diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 376aadaa7805..d060d51f9ae5 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -34,6 +34,9 @@ #define PWM_LOCK_EN (1 << 6) #define PWM_LP_DISABLE (0 << 8) +#define PWM_ONESHOT_COUNT_SHIFT 24 +#define PWM_ONESHOT_COUNT_MAX 256 + struct rockchip_pwm_chip { struct pwm_chip chip; struct clk *clk; @@ -45,6 +48,7 @@ struct rockchip_pwm_chip { unsigned long clk_rate; bool vop_pwm_en; /* indicate voppwm mirror register state */ bool center_aligned; + bool oneshot; }; struct rockchip_pwm_regs { @@ -141,6 +145,19 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ctrl &= ~PWM_ENABLE; } +#ifdef CONFIG_PWM_ROCKCHIP_ONESHOT + if (state->oneshot_count > PWM_ONESHOT_COUNT_MAX) { + pc->oneshot = false; + dev_err(chip->dev, "Oneshot_count value overflow.\n"); + } else if (state->oneshot_count > 0) { + pc->oneshot = true; + ctrl |= (state->oneshot_count - 1) << PWM_ONESHOT_COUNT_SHIFT; + } else { + pc->oneshot = false; + ctrl |= PWM_CONTINUOUS; + } +#endif + if (pc->data->supports_lock) { ctrl |= PWM_LOCK_EN; writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl); @@ -192,10 +209,13 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, val |= PWM_OUTPUT_CENTER; } - if (enable) + if (enable) { val |= enable_conf; - else + if (pc->oneshot) + val &= ~PWM_CONTINUOUS; + } else { val &= ~enable_conf; + } writel_relaxed(val, pc->base + pc->data->regs.ctrl); if (pc->data->vop_pwm) @@ -243,7 +263,7 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, */ rockchip_pwm_get_state(chip, pwm, state); - if (state->enabled) + if (state->enabled || pc->oneshot) ret = pinctrl_select_state(pc->pinctrl, pc->active_state); out: clk_disable(pc->pclk); diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 91323a4e23d7..88c16c529d04 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -84,6 +84,9 @@ struct pwm_state { enum pwm_polarity polarity; enum pwm_output_type output_type; struct pwm_output_pattern *output_pattern; +#ifdef CONFIG_PWM_ROCKCHIP_ONESHOT + u64 oneshot_count; +#endif /* CONFIG_PWM_ROCKCHIP_ONESHOT */ bool enabled; };