diff options
| author | Fenglin Wu <fenglinw@codeaurora.org> | 2017-08-14 12:45:21 +0800 |
|---|---|---|
| committer | Fenglin Wu <fenglinw@codeaurora.org> | 2017-08-16 08:38:56 +0800 |
| commit | 320e1beadf16fcc4f2d78ddf25b70270866fd63d (patch) | |
| tree | 0780b025859ad3375ed710ecbf2ed930348e1d60 /drivers/pwm/pwm-qpnp.c | |
| parent | a49bb61510b938152025049730fa922c5da950a1 (diff) | |
pwm: pwm-qpnp: Re-enable PWM output after changing mode
commit c8d3578f8b76 ("pwm: pwm-qpnp: Ignore changing period setting if
it's not requested") had fixed an issue to avoid glitches seen in PWM
output when the PWM period is not changed and the duty cycle alone is
changed. However, that didn't fix the issue completely when the LPG
channel operation mode might be configured differently even when the
duty cycle is changed and the period is unchanged. This will lead to LPG
channel getting configured to operate in a wrong mode. Fix this by
enabling PWM output whenever there is a change in the mode for LPG
channel requested by the client.
CRs-Fixed: 2070945
Change-Id: Ida6145a7cb9016e9e9116fbcd6b8ba3f6c5b3bc1
Signed-off-by: Fenglin Wu <fenglinw@codeaurora.org>
Diffstat (limited to 'drivers/pwm/pwm-qpnp.c')
| -rw-r--r-- | drivers/pwm/pwm-qpnp.c | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/drivers/pwm/pwm-qpnp.c b/drivers/pwm/pwm-qpnp.c index e46b1d583f40..2531b74b4588 100644 --- a/drivers/pwm/pwm-qpnp.c +++ b/drivers/pwm/pwm-qpnp.c @@ -328,6 +328,7 @@ struct qpnp_pwm_chip { bool enabled; struct _qpnp_pwm_config pwm_config; struct qpnp_lpg_config lpg_config; + enum pm_pwm_mode pwm_mode; spinlock_t lpg_lock; enum qpnp_lpg_revision revision; u8 sub_type; @@ -1314,12 +1315,10 @@ after_table_write: return rc; } +/* lpg_lock should be held while calling _pwm_enable() */ static int _pwm_enable(struct qpnp_pwm_chip *chip) { int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&chip->lpg_lock, flags); if (QPNP_IS_PWM_CONFIG_SELECTED( chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) || @@ -1332,8 +1331,21 @@ static int _pwm_enable(struct qpnp_pwm_chip *chip) if (!rc) chip->enabled = true; - spin_unlock_irqrestore(&chip->lpg_lock, flags); + return rc; +} + +/* lpg_lock should be held while calling _pwm_change_mode() */ +static int _pwm_change_mode(struct qpnp_pwm_chip *chip, enum pm_pwm_mode mode) +{ + int rc; + if (mode == PM_PWM_MODE_LPG) + rc = qpnp_configure_lpg_control(chip); + else + rc = qpnp_configure_pwm_control(chip); + + if (rc) + pr_err("Failed to change the mode\n"); return rc; } @@ -1410,11 +1422,15 @@ static int qpnp_pwm_enable(struct pwm_chip *pwm_chip, { int rc; struct qpnp_pwm_chip *chip = qpnp_pwm_from_pwm_chip(pwm_chip); + unsigned long flags; + spin_lock_irqsave(&chip->lpg_lock, flags); rc = _pwm_enable(chip); if (rc) pr_err("Failed to enable PWM channel: %d\n", chip->channel_id); + spin_unlock_irqrestore(&chip->lpg_lock, flags); + return rc; } @@ -1452,20 +1468,6 @@ static void qpnp_pwm_disable(struct pwm_chip *pwm_chip, chip->channel_id); } -static int _pwm_change_mode(struct qpnp_pwm_chip *chip, enum pm_pwm_mode mode) -{ - int rc; - - if (mode) - rc = qpnp_configure_lpg_control(chip); - else - rc = qpnp_configure_pwm_control(chip); - - if (rc) - pr_err("Failed to change the mode\n"); - return rc; -} - /** * pwm_change_mode - Change the PWM mode configuration * @pwm: the PWM device @@ -1490,7 +1492,22 @@ int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode) chip = qpnp_pwm_from_pwm_dev(pwm); spin_lock_irqsave(&chip->lpg_lock, flags); - rc = _pwm_change_mode(chip, mode); + if (chip->pwm_mode != mode) { + rc = _pwm_change_mode(chip, mode); + if (rc) { + pr_err("Failed to change mode: %d, rc=%d\n", mode, rc); + goto unlock; + } + chip->pwm_mode = mode; + if (chip->enabled) { + rc = _pwm_enable(chip); + if (rc) { + pr_err("Failed to enable PWM, rc=%d\n", rc); + goto unlock; + } + } + } +unlock: spin_unlock_irqrestore(&chip->lpg_lock, flags); return rc; @@ -1894,7 +1911,7 @@ out: static int qpnp_parse_dt_config(struct platform_device *pdev, struct qpnp_pwm_chip *chip) { - int rc, enable, lut_entry_size, list_size, i; + int rc, mode, lut_entry_size, list_size, i; const char *label; const __be32 *prop; u32 size; @@ -2078,18 +2095,20 @@ static int qpnp_parse_dt_config(struct platform_device *pdev, } } - rc = of_property_read_u32(of_node, "qcom,mode-select", &enable); + rc = of_property_read_u32(of_node, "qcom,mode-select", &mode); if (rc) goto read_opt_props; - if ((enable == PM_PWM_MODE_PWM && found_pwm_subnode == 0) || - (enable == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) { + if (mode > PM_PWM_MODE_LPG || + (mode == PM_PWM_MODE_PWM && found_pwm_subnode == 0) || + (mode == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) { dev_err(&pdev->dev, "%s: Invalid mode select\n", __func__); rc = -EINVAL; goto out; } - _pwm_change_mode(chip, enable); + chip->pwm_mode = mode; + _pwm_change_mode(chip, mode); _pwm_enable(chip); read_opt_props: |
