leds: leds-qpnp: replace pwm_free with pwm_disable
pwm_free() is called in the driver incorrectly when trying to disable PWM channel while changing the configuration. pwm_free() checks PWMF_REQUESTED flag before calling disable() hook. The driver doesn't call pwm_request() but only calls of_pwm_get() at the probe to get the flag once. The Flag will be cleared when pwm_free() is called for the first time and calling it afterwards will simply bailout not calling disable(). Replace pwm_free() with pwm_disable(), this won't cause any issue because the PWM channel is considered statically allocated to the led devices from hardware perspective and no need to free it in the driver. While at it, free the PWM device if any errors when getting PWM configuration. CRs-Fixed: 2014600 Change-Id: I373d2a1ac83232ce94933c287b4ebe3f23519c83 Signed-off-by: Fenglin Wu <fenglinw@codeaurora.org>
This commit is contained in:
parent
6f55033ecf
commit
5d50b169c9
1 changed files with 87 additions and 31 deletions
|
@ -897,9 +897,10 @@ static int qpnp_mpp_set(struct qpnp_led_data *led)
|
|||
}
|
||||
}
|
||||
|
||||
if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
|
||||
if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
|
||||
pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
|
||||
else {
|
||||
led->mpp_cfg->pwm_cfg->pwm_enabled = 1;
|
||||
} else {
|
||||
if (led->cdev.brightness < LED_MPP_CURRENT_MIN)
|
||||
led->cdev.brightness = LED_MPP_CURRENT_MIN;
|
||||
else {
|
||||
|
@ -950,6 +951,7 @@ static int qpnp_mpp_set(struct qpnp_led_data *led)
|
|||
led->mpp_cfg->pwm_mode =
|
||||
led->mpp_cfg->pwm_cfg->default_mode;
|
||||
pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
|
||||
led->mpp_cfg->pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
rc = qpnp_led_masked_write(led,
|
||||
LED_MPP_MODE_CTRL(led->base),
|
||||
|
@ -1606,7 +1608,7 @@ static int qpnp_kpdbl_set(struct qpnp_led_data *led)
|
|||
dev_err(&led->pdev->dev, "pwm enable failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
led->kpdbl_cfg->pwm_cfg->pwm_enabled = 1;
|
||||
set_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
|
||||
|
||||
/* is_kpdbl_master_turn_on will be set to true when GPLED1
|
||||
|
@ -1642,6 +1644,7 @@ static int qpnp_kpdbl_set(struct qpnp_led_data *led)
|
|||
"pwm enable failed\n");
|
||||
return rc;
|
||||
}
|
||||
led->kpdbl_cfg->pwm_cfg->pwm_enabled = 1;
|
||||
} else {
|
||||
if (kpdbl_master) {
|
||||
pwm_disable(kpdbl_master);
|
||||
|
@ -1660,6 +1663,7 @@ static int qpnp_kpdbl_set(struct qpnp_led_data *led)
|
|||
is_kpdbl_master_turn_on = false;
|
||||
} else {
|
||||
pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
|
||||
led->kpdbl_cfg->pwm_cfg->pwm_enabled = 0;
|
||||
clear_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
|
||||
if (bitmap_weight(kpdbl_leds_in_use,
|
||||
NUM_KPDBL_LEDS) == 1 && kpdbl_master &&
|
||||
|
@ -1727,20 +1731,17 @@ static int qpnp_rgb_set(struct qpnp_led_data *led)
|
|||
"Failed to write led enable reg\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!led->rgb_cfg->pwm_cfg->pwm_enabled) {
|
||||
pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
|
||||
led->rgb_cfg->pwm_cfg->pwm_enabled = 1;
|
||||
}
|
||||
} else {
|
||||
led->rgb_cfg->pwm_cfg->mode =
|
||||
led->rgb_cfg->pwm_cfg->default_mode;
|
||||
if (led->rgb_cfg->pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
|
||||
led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
|
||||
rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
|
||||
if (!rc)
|
||||
led->rgb_cfg->pwm_cfg->pwm_enabled = 1;
|
||||
} else {
|
||||
led->rgb_cfg->pwm_cfg->mode =
|
||||
led->rgb_cfg->pwm_cfg->default_mode;
|
||||
pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
|
||||
led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
|
||||
rc = qpnp_led_masked_write(led,
|
||||
RGB_LED_EN_CTL(led->base),
|
||||
led->rgb_cfg->enable, RGB_LED_DISABLE);
|
||||
|
@ -2183,11 +2184,17 @@ static ssize_t pwm_us_store(struct device *dev,
|
|||
previous_pwm_us = pwm_cfg->pwm_period_us;
|
||||
|
||||
pwm_cfg->pwm_period_us = pwm_us;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret) {
|
||||
pwm_cfg->pwm_period_us = previous_pwm_us;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
dev_err(&led->pdev->dev,
|
||||
|
@ -2237,12 +2244,18 @@ static ssize_t pause_lo_store(struct device *dev,
|
|||
|
||||
previous_pause_lo = pwm_cfg->lut_params.lut_pause_lo;
|
||||
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
pwm_cfg->lut_params.lut_pause_lo = pause_lo;
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret) {
|
||||
pwm_cfg->lut_params.lut_pause_lo = previous_pause_lo;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
dev_err(&led->pdev->dev,
|
||||
|
@ -2292,12 +2305,18 @@ static ssize_t pause_hi_store(struct device *dev,
|
|||
|
||||
previous_pause_hi = pwm_cfg->lut_params.lut_pause_hi;
|
||||
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
pwm_cfg->lut_params.lut_pause_hi = pause_hi;
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret) {
|
||||
pwm_cfg->lut_params.lut_pause_hi = previous_pause_hi;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
dev_err(&led->pdev->dev,
|
||||
|
@ -2348,12 +2367,18 @@ static ssize_t start_idx_store(struct device *dev,
|
|||
previous_start_idx = pwm_cfg->duty_cycles->start_idx;
|
||||
pwm_cfg->duty_cycles->start_idx = start_idx;
|
||||
pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret) {
|
||||
pwm_cfg->duty_cycles->start_idx = previous_start_idx;
|
||||
pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
dev_err(&led->pdev->dev,
|
||||
|
@ -2403,12 +2428,18 @@ static ssize_t ramp_step_ms_store(struct device *dev,
|
|||
|
||||
previous_ramp_step_ms = pwm_cfg->lut_params.ramp_step_ms;
|
||||
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
pwm_cfg->lut_params.ramp_step_ms = ramp_step_ms;
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret) {
|
||||
pwm_cfg->lut_params.ramp_step_ms = previous_ramp_step_ms;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
dev_err(&led->pdev->dev,
|
||||
|
@ -2458,12 +2489,18 @@ static ssize_t lut_flags_store(struct device *dev,
|
|||
|
||||
previous_lut_flags = pwm_cfg->lut_params.flags;
|
||||
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
pwm_cfg->lut_params.flags = lut_flags;
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret) {
|
||||
pwm_cfg->lut_params.flags = previous_lut_flags;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
dev_err(&led->pdev->dev,
|
||||
|
@ -2543,7 +2580,11 @@ static ssize_t duty_pcts_store(struct device *dev,
|
|||
pwm_cfg->old_duty_pcts = previous_duty_pcts;
|
||||
pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
|
||||
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
|
||||
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (ret)
|
||||
goto restore;
|
||||
|
@ -2558,7 +2599,10 @@ restore:
|
|||
pwm_cfg->old_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
|
||||
pwm_cfg->duty_cycles->duty_pcts = previous_duty_pcts;
|
||||
pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
qpnp_led_set(&led->cdev, led->cdev.brightness);
|
||||
return ret;
|
||||
|
@ -2588,7 +2632,10 @@ static void led_blink(struct qpnp_led_data *led,
|
|||
led->kpdbl_cfg->pwm_mode =
|
||||
pwm_cfg->default_mode;
|
||||
}
|
||||
pwm_free(pwm_cfg->pwm_dev);
|
||||
if (pwm_cfg->pwm_enabled) {
|
||||
pwm_disable(pwm_cfg->pwm_dev);
|
||||
pwm_cfg->pwm_enabled = 0;
|
||||
}
|
||||
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
|
||||
if (led->id == QPNP_ID_RGB_RED || led->id == QPNP_ID_RGB_GREEN
|
||||
|| led->id == QPNP_ID_RGB_BLUE) {
|
||||
|
@ -3541,8 +3588,11 @@ static int qpnp_get_config_kpdbl(struct qpnp_led_data *led,
|
|||
}
|
||||
|
||||
rc = qpnp_get_config_pwm(led->kpdbl_cfg->pwm_cfg, led->pdev, node);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (led->kpdbl_cfg->pwm_cfg->pwm_dev)
|
||||
pwm_put(led->kpdbl_cfg->pwm_cfg->pwm_dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(node, "qcom,row-id", &val);
|
||||
if (!rc)
|
||||
|
@ -3605,8 +3655,11 @@ static int qpnp_get_config_rgb(struct qpnp_led_data *led,
|
|||
}
|
||||
|
||||
rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->pdev, node);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (led->rgb_cfg->pwm_cfg->pwm_dev)
|
||||
pwm_put(led->rgb_cfg->pwm_cfg->pwm_dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3729,8 +3782,11 @@ static int qpnp_get_config_mpp(struct qpnp_led_data *led,
|
|||
}
|
||||
|
||||
rc = qpnp_get_config_pwm(led->mpp_cfg->pwm_cfg, led->pdev, node);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (led->mpp_cfg->pwm_cfg && led->mpp_cfg->pwm_cfg->pwm_dev)
|
||||
pwm_put(led->mpp_cfg->pwm_cfg->pwm_dev);
|
||||
goto err_config_mpp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue