blob: 93ed7dc4ce2f66a81ead529a7fb190fabf9b5364 [file] [log] [blame]
From 5b119f0f1dc8f5b0fd7e143bb12d73776d716c43 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 | 49 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 29078486534d40323015ca255c2b5d5328854b4f..181738005d9632e2db61277d431c84f0bf88819f 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -267,6 +267,7 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
pwm->chip = chip;
pwm->pwm = chip->base + i;
pwm->hwpwm = i;
+ pwm->state.output_type = PWM_OUTPUT_FIXED;
}
list_add(&chip->list, &pwm_chips);
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 8d1254761e4dd2ab465008875573c71a7ecfa3e7..1ef6899f2dc88b87271b3197e18b4ebff2bb2458 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -215,11 +215,35 @@ static ssize_t capture_show(struct device *child,
return sysfs_emit(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 cda3597b84f2c32fbe567c04b3c4114311bed02a..a6b6247e0742283ee59a61e71981f3ce33024e89 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -45,6 +45,17 @@ enum {
PWMF_EXPORTED = 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)
@@ -60,6 +71,7 @@ struct pwm_state {
u64 period;
u64 duty_cycle;
enum pwm_polarity polarity;
+ enum pwm_output_type output_type;
bool enabled;
bool usage_power;
};
@@ -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)
{
@@ -265,6 +287,7 @@ struct pwm_capture {
* @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
*/
struct pwm_ops {
int (*request)(struct pwm_chip *chip, struct pwm_device *pwm);
@@ -275,6 +298,9 @@ struct pwm_ops {
const struct pwm_state *state);
int (*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;
};
/**
@@ -310,6 +336,24 @@ struct pwm_chip {
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
@@ -418,6 +462,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.43.0.rc2.451.g8631bc7472-goog