[RFC PATCH] pwm: Add the concept of an "active" pinctrl

From: Doug Anderson
Date: Tue Sep 23 2014 - 19:17:42 EST


There are cases where you really don't want a PWM's pinctrl to take
effect until you know that the PWM is driving at the proper rate. A
good example of this is a PWM-controlled regulator, where the boot
state of the pin (maybe a pulled down input) could cause a vastly
different voltage to take effect than having the pin setup as a PWM
but not having the PWM enabled yet.

Let's add a feature where you can define an "active" pinctrl state.
This state (if it exists) will be applied after the PWM has actually
been enabled. If the PWM is ever disabled we'll go back to "default"
state.

Signed-off-by: Doug Anderson <dianders@xxxxxxxxxxxx>
---
I'm sure Linus W or Thierry or Mark will tell me this is an idiotic
idea (or totally the wrong way to do it), but I figured I'd float it
out there and maybe someone can tell me something better to do. ;)

drivers/pwm/core.c | 34 +++++++++++++++++++++++++++++++---
include/linux/pwm.h | 8 ++++++++
2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 966497d..12f86e0 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -245,6 +245,14 @@ int pwmchip_add(struct pwm_chip *chip)
if (ret < 0)
goto out;

+ chip->pinctrl = devm_pinctrl_get(chip->dev);
+ if (!IS_ERR_OR_NULL(chip->pinctrl)) {
+ chip->state_default = pinctrl_lookup_state(chip->pinctrl,
+ "default");
+ chip->state_active = pinctrl_lookup_state(chip->pinctrl,
+ "active");
+ }
+
chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL);
if (!chip->pwms) {
ret = -ENOMEM;
@@ -457,8 +465,17 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
*/
int pwm_enable(struct pwm_device *pwm)
{
- if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
- return pwm->chip->ops->enable(pwm->chip, pwm);
+ int ret;
+
+ if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
+ ret = pwm->chip->ops->enable(pwm->chip, pwm);
+
+ if (!ret && !IS_ERR_OR_NULL(pwm->chip->state_active))
+ ret = pinctrl_select_state(pwm->chip->pinctrl,
+ pwm->chip->state_active);
+
+ return ret;
+ }

return pwm ? 0 : -EINVAL;
}
@@ -470,8 +487,19 @@ EXPORT_SYMBOL_GPL(pwm_enable);
*/
void pwm_disable(struct pwm_device *pwm)
{
- if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
+ int ret;
+
+ if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags)) {
+ if (!IS_ERR_OR_NULL(pwm->chip->state_default)) {
+ ret = pinctrl_select_state(pwm->chip->pinctrl,
+ pwm->chip->state_default);
+ if (ret)
+ dev_warn(pwm->chip->dev,
+ "Couldn't set def state: %d\n", ret);
+ }
+
pwm->chip->ops->disable(pwm->chip, pwm);
+ }
}
EXPORT_SYMBOL_GPL(pwm_disable);

diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index e90628c..039c898 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -162,6 +162,10 @@ struct pwm_ops {
* @pwms: array of PWM devices allocated by the framework
* @can_sleep: must be true if the .config(), .enable() or .disable()
* operations may sleep
+ *
+ * @pinctrl: Pointer to the a pinctrl for the dev
+ * @state_default: We'll apply this when a PWM is disabled
+ * @state_active: We'll apply this when a PWM is enabled
*/
struct pwm_chip {
struct device *dev;
@@ -176,6 +180,10 @@ struct pwm_chip {
const struct of_phandle_args *args);
unsigned int of_pwm_n_cells;
bool can_sleep;
+
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *state_default;
+ struct pinctrl_state *state_active;
};

#if IS_ENABLED(CONFIG_PWM)
--
2.1.0.rc2.206.gedb03e5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/