mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user