mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
pwm: rockchip: fix frequency meter mode configurations
1.Add pinctrl config in rockchip_pwm_set_freq_meter(). 2.Add input_sel flag to select the input of io or cru. 3.Use usleep_range() instead of readl_relaxed_poll_timeout, because there is no need to poll interrupt status. Change-Id: I6ea4456539fe143baf2bfce70386c51f801a00a3 Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
This commit is contained in:
@@ -209,7 +209,7 @@
|
||||
/* FREQ_CTRL */
|
||||
#define FREQ_CTRL 0x1c4
|
||||
#define FREQ_EN(v) HIWORD_UPDATE(v, 0, 0)
|
||||
#define FREQ_CLK_SEL(v) HIWORD_UPDATE(v, 1, 2)
|
||||
#define FREQ_CLK_SEL(v) HIWORD_UPDATE(v, 1, 1)
|
||||
#define FREQ_CHANNEL_SEL(v) HIWORD_UPDATE(v, 3, 5)
|
||||
#define FREQ_CLK_SWITCH_MODE(v) HIWORD_UPDATE(v, 6, 6)
|
||||
#define FREQ_TIMIER_CLK_SEL(v) HIWORD_UPDATE(v, 7, 7)
|
||||
@@ -256,6 +256,7 @@ struct rockchip_pwm_chip {
|
||||
bool freq_meter_support;
|
||||
bool counter_support;
|
||||
bool wave_support;
|
||||
bool freq_res_valid;
|
||||
int channel_id;
|
||||
int irq;
|
||||
u8 main_version;
|
||||
@@ -281,7 +282,9 @@ struct rockchip_pwm_funcs {
|
||||
int (*get_counter_result)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
unsigned long *counter_res, bool is_clear);
|
||||
int (*set_freq_meter)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
bool enable, unsigned long delay_ms);
|
||||
unsigned long delay_ms,
|
||||
enum rockchip_pwm_freq_meter_input_sel input_sel,
|
||||
bool enable);
|
||||
int (*get_freq_meter_result)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
unsigned long delay_ms, unsigned long *freq_hz);
|
||||
int (*global_ctrl)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@@ -643,6 +646,13 @@ static irqreturn_t rockchip_pwm_irq_v4(int irq, void *data)
|
||||
writel_relaxed(CAP_LPR_INT_EN(false) | CAP_HPR_INT_EN(false), pc->base + INT_EN);
|
||||
}
|
||||
|
||||
if (val & FREQ_INT) {
|
||||
writel_relaxed(FREQ_INT, pc->base + INTSTS);
|
||||
pc->freq_res_valid = true;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (val & WAVE_MIDDLE_INT) {
|
||||
writel_relaxed(WAVE_MIDDLE_INT, pc->base + INTSTS);
|
||||
|
||||
@@ -1077,7 +1087,9 @@ err_disable_pclk:
|
||||
EXPORT_SYMBOL_GPL(rockchip_pwm_get_counter_result);
|
||||
|
||||
static int rockchip_pwm_set_freq_meter_v4(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
bool enable, unsigned long delay_ms)
|
||||
unsigned long delay_ms,
|
||||
enum rockchip_pwm_freq_meter_input_sel input_sel,
|
||||
bool enable)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
u64 div = 0;
|
||||
@@ -1085,8 +1097,14 @@ static int rockchip_pwm_set_freq_meter_v4(struct pwm_chip *chip, struct pwm_devi
|
||||
u32 arbiter = 0;
|
||||
u32 channel_sel = 0;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (enable) {
|
||||
ret = clk_enable(pc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
pc->freq_res_valid = false;
|
||||
|
||||
arbiter = BIT(pc->channel_id) << FREQ_READ_LOCK_SHIFT |
|
||||
BIT(pc->channel_id) << FREQ_GRANT_SHIFT;
|
||||
channel_sel = pc->channel_id;
|
||||
@@ -1104,9 +1122,12 @@ static int rockchip_pwm_set_freq_meter_v4(struct pwm_chip *chip, struct pwm_devi
|
||||
|
||||
writel_relaxed(FREQ_INT_EN(enable), pc->base + INT_EN);
|
||||
writel_relaxed(timer_val, pc->base + FREQ_TIMER_VALUE);
|
||||
writel_relaxed(FREQ_EN(enable) | FREQ_CHANNEL_SEL(channel_sel),
|
||||
writel_relaxed(FREQ_EN(enable) | FREQ_CLK_SEL(input_sel) | FREQ_CHANNEL_SEL(channel_sel),
|
||||
pc->base + FREQ_CTRL);
|
||||
|
||||
if (!enable)
|
||||
clk_disable(pc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1114,24 +1135,29 @@ static int rockchip_pwm_get_freq_meter_result_v4(struct pwm_chip *chip, struct p
|
||||
unsigned long delay_ms, unsigned long *freq_hz)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
int ret;
|
||||
u32 val;
|
||||
u32 freq_res;
|
||||
u32 freq_timer;
|
||||
|
||||
ret = readl_relaxed_poll_timeout(pc->base + INTSTS, val, val & FREQ_INT,
|
||||
0, delay_ms * 1000);
|
||||
if (!ret) {
|
||||
usleep_range(delay_ms * USEC_PER_MSEC, delay_ms * USEC_PER_MSEC);
|
||||
|
||||
if (pc->freq_res_valid) {
|
||||
freq_res = readl_relaxed(pc->base + FREQ_RESULT_VALUE);
|
||||
freq_timer = readl_relaxed(pc->base + FREQ_TIMER_VALUE);
|
||||
*freq_hz = DIV_ROUND_CLOSEST_ULL(pc->clk_rate * freq_res, freq_timer);
|
||||
if (!*freq_hz)
|
||||
return -EINVAL;
|
||||
|
||||
pc->freq_res_valid = false;
|
||||
} else {
|
||||
dev_err(chip->dev, "failed to wait for freq_meter interrupt\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
*freq_hz = readl_relaxed(pc->base + FREQ_RESULT_VALUE);
|
||||
if (!*freq_hz)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
enum rockchip_pwm_freq_meter_input_sel input_sel,
|
||||
unsigned long *freq_hz)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
@@ -1162,7 +1188,13 @@ int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pc->data->funcs.set_freq_meter(chip, pwm, true, delay_ms);
|
||||
ret = pinctrl_select_state(pc->pinctrl, pc->active_state);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to select pinctrl state\n");
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
ret = pc->data->funcs.set_freq_meter(chip, pwm, delay_ms, input_sel, true);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to abtain frequency meter arbitration for PWM%d\n",
|
||||
pc->channel_id);
|
||||
@@ -1173,8 +1205,9 @@ int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
pc->channel_id);
|
||||
}
|
||||
}
|
||||
pc->data->funcs.set_freq_meter(chip, pwm, false, 0);
|
||||
pc->data->funcs.set_freq_meter(chip, pwm, 0, 0, false);
|
||||
|
||||
err_disable_pclk:
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -28,6 +28,16 @@ enum rockchip_pwm_global_ctrl_cmd {
|
||||
PWM_GLOBAL_CTRL_DISABLE,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum rockchip_pwm_freq_meter_input_sel - select the input src of frequency meter
|
||||
* @PWM_FREQ_METER_INPUT_FROM_IO: input from PWM IO
|
||||
* @PWM_FREQ_METER_INPUT_FROM_CRU: input from CRU
|
||||
*/
|
||||
enum rockchip_pwm_freq_meter_input_sel {
|
||||
PWM_FREQ_METER_INPUT_FROM_IO,
|
||||
PWM_FREQ_METER_INPUT_FROM_CRU,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_pwm_wave_table - wave table config object
|
||||
* @offset: the offset of wave table to set
|
||||
@@ -129,11 +139,13 @@ int rockchip_pwm_get_counter_result(struct pwm_device *pwm,
|
||||
* rockchip_pwm_set_freq_meter() - setup pwm frequency meter mode
|
||||
* @pwm: PWM device
|
||||
* @delay_ms: time to wait, in milliseconds, before getting frequency meter result
|
||||
* @input_sel: selec the input of frequency meter
|
||||
* @freq_hz: parameter in Hz to fill with frequency meter result
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
enum rockchip_pwm_freq_meter_input_sel input_sel,
|
||||
unsigned long *freq_hz);
|
||||
|
||||
/**
|
||||
@@ -166,6 +178,7 @@ static inline int rockchip_pwm_get_counter_result(struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
static inline int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
enum rockchip_pwm_freq_meter_input_sel input_sel,
|
||||
unsigned long *freq_hz)
|
||||
{
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user