pwm: rockchip: use the completion to check whether biphasic result is valid

In some cases, the discontinuous biphasic result may not be valid
after sleeping for specified time due to the interrupt preemption.
Therefore, it may be better to use the completion and set the actual
wait time to the 3/2 of the specified delay time.

Change-Id: Ib7ee5f7ceb53c195178e25d745985577fa8a6c4c
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
This commit is contained in:
Damon Ding
2025-04-16 14:13:08 +08:00
committed by Tao Huang
parent 4fcd88017a
commit 856d44d638

View File

@@ -315,6 +315,7 @@ struct rockchip_pwm_chip {
struct dentry *debugfs;
struct completion ir_trans_completion;
struct completion freq_meter_completion;
struct completion biphasic_completion;
void __iomem *base;
unsigned long clk_rate;
unsigned long is_clk_enabled;
@@ -330,7 +331,6 @@ struct rockchip_pwm_chip {
bool wave_support;
bool biphasic_support;
bool ledc_support;
bool biphasic_res_valid;
int channel_id;
int irq;
u32 scaler;
@@ -747,7 +747,8 @@ static irqreturn_t rockchip_pwm_irq_v4(int irq, void *data)
if (val & BIPHASIC_INT) {
writel_relaxed(BIPHASIC_INT, pc->base + INTSTS);
pc->biphasic_res_valid = true;
complete(&pc->biphasic_completion);
ret = IRQ_HANDLED;
}
@@ -1737,7 +1738,9 @@ static int rockchip_pwm_set_biphasic_v4(struct pwm_chip *chip, struct pwm_device
ret = clk_enable(pc->clk);
if (ret)
return ret;
pc->biphasic_res_valid = false;
if (!config->is_continuous)
reinit_completion(&pc->biphasic_completion);
ctrl = BIPHASIC_EN(true) |
BIPHASIC_CONTINOUS_MODE_EN(config->is_continuous) |
@@ -1833,27 +1836,28 @@ static int rockchip_pwm_get_biphasic_result_v4(struct pwm_chip *chip, struct pwm
const struct rockchip_pwm_biphasic_config *config = pc->biphasic_config;
u32 val;
u32 biphasic_timer;
int ret = 0;
if (!config->is_continuous) {
usleep_range(config->delay_ms * USEC_PER_MSEC, config->delay_ms * USEC_PER_MSEC);
if (pc->biphasic_res_valid) {
*biphasic_res = readl_relaxed(pc->base + BIPHASIC_RESULT_VALUE);
if (!*biphasic_res)
return -EINVAL;
if (pc->biphasic_config->mode == PWM_BIPHASIC_COUNTER_MODE0_FREQ) {
val = *biphasic_res;
biphasic_timer = readl_relaxed(pc->base + BIPHASIC_TIMER_VALUE);
*biphasic_res = DIV_ROUND_CLOSEST_ULL((u64)pc->clk_rate * val,
biphasic_timer);
}
pc->biphasic_res_valid = false;
} else {
dev_err(chip->dev, "failed to wait for biphasic counter interrupt\n");
ret = wait_for_completion_timeout(&pc->biphasic_completion,
msecs_to_jiffies(config->delay_ms * 3 / 2));
if (!ret) {
dev_err(chip->dev,
"Failed to wait for PWM%d biphasic counter result to be valid\n",
pc->channel_id);
return -ETIMEDOUT;
}
*biphasic_res = readl_relaxed(pc->base + BIPHASIC_RESULT_VALUE);
if (!*biphasic_res)
return -EINVAL;
if (pc->biphasic_config->mode == PWM_BIPHASIC_COUNTER_MODE0_FREQ) {
val = *biphasic_res;
biphasic_timer = readl_relaxed(pc->base + BIPHASIC_TIMER_VALUE);
*biphasic_res = DIV_ROUND_CLOSEST_ULL((u64)pc->clk_rate * val,
biphasic_timer);
}
} else {
*biphasic_res = readl_relaxed(pc->base + BIPHASIC_RESULT_VALUE_SYNC);
}
@@ -2376,6 +2380,9 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
if (pc->freq_meter_support)
init_completion(&pc->freq_meter_completion);
if (pc->biphasic_support)
init_completion(&pc->biphasic_completion);
if (pc->data->funcs.irq_handler) {
/*
* For pwm v1-v3, the older platform may not support interrupt, and