mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
pwm: rockchip: disable the pclk dynamic switch if oneshot mode enabled
If the pclk of pwm is off, the interrupt will not be generated. Signed-off-by: Damon Ding <damon.ding@rock-chips.com> Change-Id: I1c68a22e875712fd7260ba8f24bd8f53cb8aa679
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -25,7 +26,11 @@
|
||||
#define PWM_CTRL_OUTPUT_EN (1 << 3)
|
||||
|
||||
#define PWM_ENABLE (1 << 0)
|
||||
#define PWM_CONTINUOUS (1 << 1)
|
||||
#define PWM_MODE_SHIFT 1
|
||||
#define PWM_MODE_MASK (0x3 << PWM_MODE_SHIFT)
|
||||
#define PWM_ONESHOT (0 << PWM_MODE_SHIFT)
|
||||
#define PWM_CONTINUOUS (1 << PWM_MODE_SHIFT)
|
||||
#define PWM_CAPTURE (2 << PWM_MODE_SHIFT)
|
||||
#define PWM_DUTY_POSITIVE (1 << 3)
|
||||
#define PWM_DUTY_NEGATIVE (0 << 3)
|
||||
#define PWM_INACTIVE_NEGATIVE (0 << 4)
|
||||
@@ -56,7 +61,7 @@ struct rockchip_pwm_chip {
|
||||
unsigned long clk_rate;
|
||||
bool vop_pwm_en; /* indicate voppwm mirror register state */
|
||||
bool center_aligned;
|
||||
bool oneshot;
|
||||
bool oneshot_en;
|
||||
int channel_id;
|
||||
int irq;
|
||||
};
|
||||
@@ -93,9 +98,11 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return;
|
||||
if (!pc->oneshot_en) {
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = readl_relaxed(pc->base + pc->data->regs.period);
|
||||
tmp *= pc->data->prescaler * NSEC_PER_SEC;
|
||||
@@ -106,6 +113,8 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pc->clk_rate);
|
||||
|
||||
val = readl_relaxed(pc->base + pc->data->regs.ctrl);
|
||||
if (pc->oneshot_en)
|
||||
enable_conf &= ~PWM_CONTINUOUS;
|
||||
state->enabled = (val & enable_conf) == enable_conf;
|
||||
|
||||
if (pc->data->supports_polarity && !(val & PWM_DUTY_POSITIVE))
|
||||
@@ -113,7 +122,8 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
else
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
clk_disable(pc->pclk);
|
||||
if (!pc->oneshot_en)
|
||||
clk_disable(pc->pclk);
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_pwm_oneshot_irq(int irq, void *data)
|
||||
@@ -179,13 +189,13 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
#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) {
|
||||
if (state->oneshot_count > 0 && state->oneshot_count <= PWM_ONESHOT_COUNT_MAX) {
|
||||
u32 int_ctrl;
|
||||
|
||||
pc->oneshot = true;
|
||||
pc->oneshot_en = true;
|
||||
ctrl &= ~PWM_MODE_MASK;
|
||||
ctrl |= PWM_ONESHOT;
|
||||
|
||||
ctrl &= ~PWM_ONESHOT_COUNT_MASK;
|
||||
ctrl |= (state->oneshot_count - 1) << PWM_ONESHOT_COUNT_SHIFT;
|
||||
|
||||
@@ -195,9 +205,15 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
} else {
|
||||
u32 int_ctrl;
|
||||
|
||||
pc->oneshot = false;
|
||||
if (state->oneshot_count)
|
||||
dev_err(chip->dev, "Oneshot_count must be between 1 and 256.\n");
|
||||
|
||||
pc->oneshot_en = false;
|
||||
ctrl &= ~PWM_MODE_MASK;
|
||||
ctrl |= PWM_CONTINUOUS;
|
||||
|
||||
ctrl &= ~PWM_ONESHOT_COUNT_MASK;
|
||||
|
||||
int_ctrl = readl_relaxed(pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
int_ctrl &= ~PWM_CH_INT(pc->channel_id);
|
||||
writel_relaxed(int_ctrl, pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
@@ -257,7 +273,7 @@ static int rockchip_pwm_enable(struct pwm_chip *chip,
|
||||
|
||||
if (enable) {
|
||||
val |= enable_conf;
|
||||
if (pc->oneshot)
|
||||
if (pc->oneshot_en)
|
||||
val &= ~PWM_CONTINUOUS;
|
||||
} else {
|
||||
val &= ~enable_conf;
|
||||
@@ -281,9 +297,11 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
bool enabled;
|
||||
int ret = 0;
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!pc->oneshot_en) {
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pwm_get_state(pwm, &curstate);
|
||||
enabled = curstate.enabled;
|
||||
@@ -306,7 +324,8 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (state->enabled)
|
||||
ret = pinctrl_select_state(pc->pinctrl, pc->active_state);
|
||||
out:
|
||||
clk_disable(pc->pclk);
|
||||
if (!pc->oneshot_en)
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -537,7 +556,27 @@ err_clk:
|
||||
static int rockchip_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
struct pwm_state state;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* For oneshot mode, it is needed to wait for bit PWM_ENABLE
|
||||
* to 0, which is automatic if all periods have been sent.
|
||||
*/
|
||||
pwm_get_state(&pc->chip.pwms[0], &state);
|
||||
if (state.enabled) {
|
||||
if (pc->oneshot_en) {
|
||||
if (readl_poll_timeout(pc->base + pc->data->regs.ctrl,
|
||||
val, !(val & PWM_ENABLE), 1000, 10 * 1000))
|
||||
dev_err(&pdev->dev, "Wait for oneshot to complete failed\n");
|
||||
} else {
|
||||
state.enabled = false;
|
||||
pwm_apply_state(&pc->chip.pwms[0], &state);
|
||||
}
|
||||
}
|
||||
|
||||
if (pc->oneshot_en)
|
||||
clk_disable(pc->pclk);
|
||||
clk_unprepare(pc->pclk);
|
||||
clk_unprepare(pc->clk);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user