pwm: qcom: Add reset support functionality

Add pwm reset support so that for each frame, period and
duty_cycle can be changed dynamically. While at it, also
update the pdm_pwm_free API with PWM disable functionality.

Change-Id: I64ecd4a8cec948d56cb89e7a5ae4b30e70cb9f3e
Signed-off-by: Kalpak Kawadkar <quic_kkawadka@quicinc.com>
This commit is contained in:
Kalpak Kawadkar 2024-08-06 10:40:25 +05:30
parent 8197181c0a
commit f7ab05e15e

View File

@ -29,8 +29,11 @@
#define PWM_CYC_CFG 0xC #define PWM_CYC_CFG 0xC
#define PWM_UPDATE 0x10 #define PWM_UPDATE 0x10
#define PWM_PERIOD_CNT 0x14 #define PWM_PERIOD_CNT 0x14
#define PWM_RESET 0x18
#define PWM_FRAME_POLARITY_BIT 0 #define PWM_FRAME_POLARITY_BIT BIT(0)
#define PWM_FRAME_ROLLOVER_CNT_BIT BIT(4)
#define PWM_FRAME_RESET_BIT BIT(0)
enum { enum {
ENABLE_STATUS0, ENABLE_STATUS0,
@ -42,6 +45,8 @@ enum {
struct pdm_pwm_priv_data { struct pdm_pwm_priv_data {
unsigned int max_channels; unsigned int max_channels;
const u16 *status_reg_offsets; const u16 *status_reg_offsets;
bool pwm_reset_support;
bool pwm_cnt_rollover;
}; };
/* /*
@ -54,6 +59,7 @@ struct pdm_pwm_priv_data {
* @current_freq: Current frequency of frame. * @current_freq: Current frequency of frame.
* @freq_set: This bool flag is responsible for setting period once per frame. * @freq_set: This bool flag is responsible for setting period once per frame.
* @mutex: mutex lock per frame. * @mutex: mutex lock per frame.
* @cnt_rollover_en: This bool flag is used to set rollover bit per frame.
*/ */
struct pdm_pwm_frames { struct pdm_pwm_frames {
u32 frame_id; u32 frame_id;
@ -66,6 +72,7 @@ struct pdm_pwm_frames {
bool freq_set; bool freq_set;
struct mutex frame_lock; /* PWM per frame lock */ struct mutex frame_lock; /* PWM per frame lock */
struct pdm_pwm_chip *pwm_chip; struct pdm_pwm_chip *pwm_chip;
bool cnt_rollover_en;
}; };
/* /*
@ -100,8 +107,11 @@ static int __pdm_pwm_calc_pwm_frequency(struct pdm_pwm_chip *chip,
unsigned long cyc_cfg, freq; unsigned long cyc_cfg, freq;
int ret; int ret;
/* PWM client could set the period only once, due to HW limitation. */ /*
if (chip->frames[hw_idx].freq_set) * PWM client can set the period only once if the HW version does
* not support reset functionality.
*/
if (chip->frames[hw_idx].freq_set && !chip->priv_data->pwm_reset_support)
return 0; return 0;
freq = PERIOD_TO_HZ(period_ns); freq = PERIOD_TO_HZ(period_ns);
@ -167,18 +177,34 @@ static int pdm_pwm_config(struct pdm_pwm_chip *chip, u32 hw_idx,
mutex_lock(&chip->frames[hw_idx].frame_lock); mutex_lock(&chip->frames[hw_idx].frame_lock);
/*
* Set the counter rollover enable bit, so that counter doesn't get stuck
* in period change configuration.
*/
if (chip->priv_data->pwm_cnt_rollover && !chip->frames[hw_idx].cnt_rollover_en) {
regmap_update_bits(chip->regmap, chip->frames[hw_idx].reg_offset + PWM_CTL0,
PWM_FRAME_ROLLOVER_CNT_BIT, PWM_FRAME_ROLLOVER_CNT_BIT);
chip->frames[hw_idx].cnt_rollover_en = true;
}
ret = __pdm_pwm_calc_pwm_frequency(chip, current_period, hw_idx); ret = __pdm_pwm_calc_pwm_frequency(chip, current_period, hw_idx);
if (ret) if (ret)
goto out; goto out;
if (chip->frames[hw_idx].current_period_ns != period_ns) { if (chip->frames[hw_idx].current_period_ns != period_ns) {
pr_err("Period cannot be updated, calculating dutycycle on old period\n"); if (chip->priv_data->pwm_reset_support)
current_period = chip->frames[hw_idx].current_period_ns; regmap_update_bits(chip->regmap,
chip->frames[hw_idx].reg_offset + PWM_RESET,
PWM_FRAME_RESET_BIT, PWM_FRAME_RESET_BIT);
else {
pr_err("Period cannot be updated, calculating dutycycle on old period\n");
current_period = chip->frames[hw_idx].current_period_ns;
}
} }
if (chip->frames[hw_idx].polarity != polarity) { if (chip->frames[hw_idx].polarity != polarity) {
regmap_update_bits(chip->regmap, chip->frames[hw_idx].reg_offset regmap_update_bits(chip->regmap, chip->frames[hw_idx].reg_offset
+ PWM_CTL0, BIT(PWM_FRAME_POLARITY_BIT), polarity); + PWM_CTL0, PWM_FRAME_POLARITY_BIT, polarity);
chip->frames[hw_idx].polarity = polarity; chip->frames[hw_idx].polarity = polarity;
} }
@ -220,21 +246,6 @@ static int pdm_pwm_config(struct pdm_pwm_chip *chip, u32 hw_idx,
return ret; return ret;
} }
static void pdm_pwm_free(struct pwm_chip *pwm_chip, struct pwm_device *pwm)
{
struct pdm_pwm_chip *chip = container_of(pwm_chip,
struct pdm_pwm_chip, pwm_chip);
u32 hw_idx = pwm->hwpwm;
mutex_lock(&chip->lock);
chip->frames[hw_idx].freq_set = false;
chip->frames[hw_idx].current_period_ns = 0;
chip->frames[hw_idx].current_duty_ns = 0;
mutex_unlock(&chip->lock);
}
static int pdm_pwm_enable(struct pdm_pwm_chip *chip, struct pwm_device *pwm) static int pdm_pwm_enable(struct pdm_pwm_chip *chip, struct pwm_device *pwm)
{ {
u32 ret, val; u32 ret, val;
@ -305,7 +316,7 @@ static int pdm_pwm_apply(struct pwm_chip *pwm_chip, struct pwm_device *pwm,
pwm_get_state(pwm, &curr_state); pwm_get_state(pwm, &curr_state);
if (state->period < curr_state.period) if (state->period < curr_state.period && !chip->priv_data->pwm_reset_support)
return -EINVAL; return -EINVAL;
if (state->period != curr_state.period || if (state->period != curr_state.period ||
@ -331,6 +342,24 @@ static int pdm_pwm_apply(struct pwm_chip *pwm_chip, struct pwm_device *pwm,
return 0; return 0;
} }
static void pdm_pwm_free(struct pwm_chip *pwm_chip, struct pwm_device *pwm)
{
struct pdm_pwm_chip *chip = container_of(pwm_chip,
struct pdm_pwm_chip, pwm_chip);
u32 hw_idx = pwm->hwpwm;
mutex_lock(&chip->lock);
chip->frames[hw_idx].freq_set = false;
chip->frames[hw_idx].current_period_ns = 0;
chip->frames[hw_idx].current_duty_ns = 0;
chip->frames[hw_idx].cnt_rollover_en = false;
mutex_unlock(&chip->lock);
pdm_pwm_disable(chip, pwm);
}
static const struct pwm_ops pdm_pwm_ops = { static const struct pwm_ops pdm_pwm_ops = {
.apply = pdm_pwm_apply, .apply = pdm_pwm_apply,
.free = pdm_pwm_free, .free = pdm_pwm_free,
@ -465,7 +494,7 @@ static int get_polarity(struct seq_file *m, void *unused)
u32 temp; u32 temp;
regmap_read(chip->regmap, frame->reg_offset + PWM_CTL0, &temp); regmap_read(chip->regmap, frame->reg_offset + PWM_CTL0, &temp);
if (BIT(PWM_FRAME_POLARITY_BIT) & temp) if (PWM_FRAME_POLARITY_BIT & temp)
seq_puts(m, "PWM_POLARITY_INVERSED\n"); seq_puts(m, "PWM_POLARITY_INVERSED\n");
else else
seq_puts(m, "PWM_POLARITY_NORMAL\n"); seq_puts(m, "PWM_POLARITY_NORMAL\n");
@ -672,6 +701,8 @@ static struct pdm_pwm_priv_data pdm_pwm_v2_reg_offsets = {
[ENABLE_STATUS0] = 0xc, [ENABLE_STATUS0] = 0xc,
[ENABLE_STATUS1] = 0x10, [ENABLE_STATUS1] = 0x10,
}, },
.pwm_reset_support = true,
.pwm_cnt_rollover = true,
}; };
static const struct of_device_id pdm_pwm_of_match[] = { static const struct of_device_id pdm_pwm_of_match[] = {