Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 325e6de0 authored by Fenglin Wu's avatar Fenglin Wu Committed by Subbaraman Narayanamurthy
Browse files

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: default avatarFenglin Wu <fenglinw@codeaurora.org>
parent b7c54a95
Loading
Loading
Loading
Loading
+87 −31
Original line number Diff line number Diff line
@@ -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;
		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 @@ static ssize_t duty_pcts_store(struct device *dev,
	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;