From 0963865b683ef5e1e5df2e06e691e9620edb7351 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 22 Sep 2021 16:14:19 -0700 Subject: [PATCH] pwm: pwm-qti-lpg: add qpnp_lpg_pwm_{set_output_type,get_output_types_supported} 'Commit 106a4b85e08f ("BACKPORT: FROMLIST: pwm: Add support for different PWM output types")' cannot be carried forward. Hence to support breath functionality in leds-qti-tri-led driver, add the following APIs. - qpnp_lpg_pwm_set_output_type - qpnp_lpg_pwm_get_output_types_supported This is needed to switch PWM output type to PWM (fixed) or LPG/PPG (modulated). Change-Id: I932dd03dea35377727fb28bafa87cfbcf7e95c97 Signed-off-by: Subbaraman Narayanamurthy --- drivers/pwm/pwm-qti-lpg.c | 83 ++++++++++++++++++++---------------- include/linux/qpnp/qti-pwm.h | 42 ++++++++++++++++++ 2 files changed, 88 insertions(+), 37 deletions(-) create mode 100644 include/linux/qpnp/qti-pwm.h diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index a7f77dbdd5f6..213a79b6e20c 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -186,6 +187,7 @@ struct qpnp_lpg_channel { struct qpnp_lpg_chip *chip; struct lpg_pwm_config pwm_config; struct lpg_ramp_config ramp_config; + enum pwm_output_type output_type; u32 lpg_idx; u32 reg_base; u32 max_pattern_length; @@ -1213,7 +1215,7 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) break; lpg_idx = chip->lpg_group[i] - 1; pwm = &chip->pwm_chip.pwms[lpg_idx]; - if ((pwm_get_output_type(pwm) == PWM_OUTPUT_MODULATED) + if ((lpg->output_type == PWM_OUTPUT_MODULATED) && pwm_is_enabled(pwm)) { rc = qpnp_lpg_masked_write(&chip->lpgs[lpg_idx], REG_LPG_ENABLE_CONTROL, @@ -1240,17 +1242,22 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) return rc; } -static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, - struct pwm_device *pwm, enum pwm_output_type output_type) +int qpnp_lpg_pwm_set_output_type(struct pwm_device *pwm, + enum pwm_output_type output_type) { struct qpnp_lpg_channel *lpg; enum lpg_src src_sel; int rc; bool is_enabled; - lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); + if (!pwm) { + pr_err("pwm cannot be NULL\n"); + return -ENODEV; + } + + lpg = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); if (lpg == NULL) { - dev_err(pwm_chip->dev, "lpg not found\n"); + dev_err(pwm->chip->dev, "lpg not found\n"); return -ENODEV; } @@ -1259,6 +1266,9 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, return 0; } + if (output_type == lpg->output_type) + return 0; + src_sel = (output_type == PWM_OUTPUT_MODULATED) ? LUT_PATTERN : PWM_VALUE; if (src_sel == lpg->src_sel) @@ -1275,7 +1285,7 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, */ rc = qpnp_lpg_pwm_src_enable(lpg, false); if (rc < 0) { - dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", + dev_err(pwm->chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); return rc; } @@ -1297,7 +1307,7 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, rc = qpnp_lpg_set_ramp_config(lpg); if (rc < 0) { - dev_err(pwm_chip->dev, "Config LPG%d ramping failed, rc=%d\n", + dev_err(pwm->chip->dev, "Config LPG%d ramping failed, rc=%d\n", lpg->lpg_idx, rc); return rc; } @@ -1308,21 +1318,47 @@ static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, if (is_enabled) { rc = qpnp_lpg_set_pwm_config(lpg); if (rc < 0) { - dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n", + dev_err(pwm->chip->dev, "Config PWM failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); return rc; } rc = qpnp_lpg_pwm_src_enable(lpg, true); if (rc < 0) { - dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", + dev_err(pwm->chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); return rc; } } + lpg->output_type = output_type; + return 0; } +EXPORT_SYMBOL(qpnp_lpg_pwm_set_output_type); + +int qpnp_lpg_pwm_get_output_types_supported(struct pwm_device *pwm) +{ + enum pwm_output_type type = PWM_OUTPUT_FIXED; + struct qpnp_lpg_channel *lpg; + + if (!pwm) { + pr_err("pwm cannot be NULL\n"); + return -ENODEV; + } + + lpg = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + if (lpg == NULL) { + dev_err(pwm->chip->dev, "lpg not found\n"); + return -ENODEV; + } + + if (lpg->chip->lut != NULL) + type |= PWM_OUTPUT_MODULATED; + + return type; +} +EXPORT_SYMBOL(qpnp_lpg_pwm_get_output_types_supported); static int qpnp_lpg_pwm_enable(struct pwm_chip *pwm_chip, struct pwm_device *pwm) @@ -1389,38 +1425,11 @@ static void qpnp_lpg_pwm_disable(struct pwm_chip *pwm_chip, rc); } -static int qpnp_lpg_pwm_output_types_supported(struct pwm_chip *pwm_chip, - struct pwm_device *pwm) -{ - enum pwm_output_type type = PWM_OUTPUT_FIXED; - struct qpnp_lpg_channel *lpg; - - lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); - if (lpg == NULL) { - dev_err(pwm_chip->dev, "lpg not found\n"); - return type; - } - - if (lpg->chip->lut != NULL) - type |= PWM_OUTPUT_MODULATED; - - return type; -} - static int qpnp_lpg_pwm_apply(struct pwm_chip *pwm_chip, struct pwm_device *pwm, const struct pwm_state *state) { int rc; - if (state->output_type != pwm->state.output_type) { - rc = qpnp_lpg_pwm_set_output_type(pwm->chip, pwm, - state->output_type); - if (rc < 0) - return rc; - - pwm->state.output_type = state->output_type; - } - if (state->period != pwm->state.period || state->duty_cycle != pwm->state.duty_cycle) { rc = qpnp_lpg_pwm_config(pwm->chip, pwm, @@ -1449,7 +1458,6 @@ static int qpnp_lpg_pwm_apply(struct pwm_chip *pwm_chip, struct pwm_device *pwm, static const struct pwm_ops qpnp_lpg_pwm_ops = { .apply = qpnp_lpg_pwm_apply, - .get_output_type_supported = qpnp_lpg_pwm_output_types_supported, .owner = THIS_MODULE, }; @@ -1963,6 +1971,7 @@ static int qpnp_lpg_probe(struct platform_device *pdev) for (i = 0; i < chip->num_lpgs; i++) { lpg = &chip->lpgs[i]; + lpg->output_type = PWM_OUTPUT_FIXED; if (lpg->enable_pfm) { rc = qpnp_lpg_write(lpg, REG_PWM_FM_MODE, FM_MODE_ENABLE); diff --git a/include/linux/qpnp/qti-pwm.h b/include/linux/qpnp/qti-pwm.h new file mode 100644 index 000000000000..1d2a75376e3a --- /dev/null +++ b/include/linux/qpnp/qti-pwm.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _QTI_PWM_H +#define _QTI_PWM_H + +#include +#include +#include +#include + +/** + * enum pwm_output_type - output type of the PWM signal + * @PWM_OUTPUT_FIXED: PWM output is fixed until a change request + * @PWM_OUTPUT_MODULATED: PWM output is modulated in hardware + * autonomously with a predefined pattern + */ +enum pwm_output_type { + PWM_OUTPUT_FIXED = BIT(0), + PWM_OUTPUT_MODULATED = BIT(1), +}; + +#if IS_ENABLED(CONFIG_PWM_QTI_LPG) +int qpnp_lpg_pwm_get_output_types_supported(struct pwm_device *pwm); +int qpnp_lpg_pwm_set_output_type(struct pwm_device *pwm, + enum pwm_output_type output_type); +#else +static inline int +qpnp_lpg_pwm_get_output_types_supported(struct pwm_device *pwm) +{ + return -EINVAL; +} +static inline int qpnp_lpg_pwm_set_output_type(struct pwm_device *pwm, + enum pwm_output_type output_type) +{ + return -EINVAL; +} +#endif + +#endif