OSDN Git Service

leds: leds-qpnp: replace pwm_free with pwm_disable
authorFenglin Wu <fenglinw@codeaurora.org>
Thu, 16 Mar 2017 05:40:26 +0000 (13:40 +0800)
committerFenglin Wu <fenglinw@codeaurora.org>
Fri, 17 Mar 2017 04:49:41 +0000 (12:49 +0800)
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>
drivers/leds/leds-qpnp.c

index 85a6be8..817dfa3 100644 (file)
@@ -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_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)
+               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;
-               pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
-               led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
+               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 = 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;