blob: 0e816f4975147393acf6bdbd3bf0288c85db47aa [file] [log] [blame]
From ada7fa60246a3ed64a66f8989730f89113492af7 Mon Sep 17 00:00:00 2001
From: Fenglin Wu <fenglinw@codeaurora.org>
Date: Mon, 4 Dec 2017 09:56:51 +0800
Subject: [PATCH] BACKPORT: FROMLIST: pwm: Add support for different PWM output
types
Normally, PWM channels have fixed output until software requests to
change their settings. There are some PWM devices whose outputs can be
changed autonomously according to a predefined pattern programmed in
hardware.
Add support for such devices by adding a new pwm_output_type enum type
to identify these two different PWM types and adding helper functions to
read the PWM output type supported by a PWM.
Bug: 140290585
Link: https://lore.kernel.org/lkml/1568415464-20267-1-git-send-email-gurus@codeaurora.org/
Change-Id: Ie8d61975057c51258e5bde9451ce96be4acdf98b
Signed-off-by: Fenglin Wu <fenglinw@codeaurora.org>
[gurus@codeaurora.org: removed output_pattern, changed output_type sysfs
param to read-only, reworded commit message]
Signed-off-by: Guru Das Srinagesh <gurus@codeaurora.org>
---
drivers/pwm/core.c | 1 +
drivers/pwm/sysfs.c | 25 +++++++++++++++++++++++
include/linux/pwm.h | 48 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c4d5c0667137..b7f761970c2b 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -289,6 +289,7 @@ int pwmchip_add(struct pwm_chip *chip)
pwm->chip = chip;
pwm->pwm = chip->base + i;
pwm->hwpwm = i;
+ pwm->state.output_type = PWM_OUTPUT_FIXED;
radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
}
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 9903c3a7eced..f5f376604436 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -215,11 +215,35 @@ static ssize_t capture_show(struct device *child,
return sprintf(buf, "%u %u\n", result.period, result.duty_cycle);
}
+static ssize_t output_type_show(struct device *child,
+ struct device_attribute *attr,
+ char *buf)
+{
+ const struct pwm_device *pwm = child_to_pwm_device(child);
+ const char *output_type = "unknown";
+ struct pwm_state state;
+
+ pwm_get_state(pwm, &state);
+ switch (state.output_type) {
+ case PWM_OUTPUT_FIXED:
+ output_type = "fixed";
+ break;
+ case PWM_OUTPUT_MODULATED:
+ output_type = "modulated";
+ break;
+ default:
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", output_type);
+}
+
static DEVICE_ATTR_RW(period);
static DEVICE_ATTR_RW(duty_cycle);
static DEVICE_ATTR_RW(enable);
static DEVICE_ATTR_RW(polarity);
static DEVICE_ATTR_RO(capture);
+static DEVICE_ATTR_RO(output_type);
static struct attribute *pwm_attrs[] = {
&dev_attr_period.attr,
@@ -227,6 +251,7 @@ static struct attribute *pwm_attrs[] = {
&dev_attr_enable.attr,
&dev_attr_polarity.attr,
&dev_attr_capture.attr,
+ &dev_attr_output_type.attr,
NULL
};
ATTRIBUTE_GROUPS(pwm);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 5bb90af4997e..53420838de36 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -48,6 +48,17 @@ enum {
PWMF_EXPORTED = 1 << 1,
};
+/**
+ * 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 = 1 << 0,
+ PWM_OUTPUT_MODULATED = 1 << 1,
+};
+
/*
* struct pwm_state - state of a PWM channel
* @period: PWM period (in nanoseconds)
@@ -59,6 +70,7 @@ struct pwm_state {
u64 period;
u64 duty_cycle;
enum pwm_polarity polarity;
+ enum pwm_output_type output_type;
bool enabled;
};
@@ -151,6 +163,16 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
return state.polarity;
}
+static inline enum pwm_output_type pwm_get_output_type(
+ const struct pwm_device *pwm)
+{
+ struct pwm_state state;
+
+ pwm_get_state(pwm, &state);
+
+ return state.output_type;
+}
+
static inline void pwm_get_args(const struct pwm_device *pwm,
struct pwm_args *args)
{
@@ -254,6 +276,7 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
* @get_state: get the current PWM state. This function is only
* called once per PWM device when the PWM chip is
* registered.
+ * @get_output_type_supported: get the supported output type of this PWM
* @owner: helps prevent removal of modules exporting active PWMs
* @config: configure duty cycles and period length for this PWM
* @set_polarity: configure the polarity of this PWM
@@ -269,6 +292,8 @@ struct pwm_ops {
const struct pwm_state *state);
void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state);
+ int (*get_output_type_supported)(struct pwm_chip *chip,
+ struct pwm_device *pwm);
struct module *owner;
/* Only used by legacy drivers */
@@ -323,6 +348,24 @@ void pwm_free(struct pwm_device *pwm);
int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state);
int pwm_adjust_config(struct pwm_device *pwm);
+/**
+ * pwm_get_output_type_supported() - obtain output type of a PWM device.
+ * @pwm: PWM device
+ *
+ * Returns: output type supported by the PWM device
+ */
+static inline int pwm_get_output_type_supported(struct pwm_device *pwm)
+{
+ if (!pwm)
+ return -EINVAL;
+
+ if (pwm->chip->ops->get_output_type_supported)
+ return pwm->chip->ops->get_output_type_supported(pwm->chip,
+ pwm);
+
+ return PWM_OUTPUT_FIXED;
+}
+
/**
* pwm_config() - change a PWM device configuration
* @pwm: PWM device
@@ -439,6 +482,11 @@ static inline int pwm_adjust_config(struct pwm_device *pwm)
return -ENOTSUPP;
}
+static inline int pwm_get_output_type_supported(struct pwm_device *pwm)
+{
+ return -EINVAL;
+}
+
static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
int period_ns)
{
--
2.31.1.607.g51e8a6a459-goog