]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
pwm: core: Add support to read tachometer via pwm capture
authorLaxman Dewangan <ldewangan@nvidia.com>
Wed, 12 Apr 2017 17:35:46 +0000 (23:05 +0530)
committerBharat Nihalani <bnihalani@nvidia.com>
Mon, 13 Nov 2017 08:56:40 +0000 (00:56 -0800)
Add support for tachometer driver via PWM core framework.
For this add PWM HW call backs for setting capture-window-length,
read RPM.

Also add sysfs for configuring window length and reading RPM
from user space.

bug 200237693

Change-Id: I1a80150c70434769f9fc23c9b0cf1fabe6729665
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/1461621
Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com>
Reviewed-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
GVS: Gerrit_Virtual_Submit
(cherry picked from commit fe2668e0ef22443a611f7a26b89cf906f21a606d)

drivers/pwm/core.c
drivers/pwm/sysfs.c
include/linux/pwm.h

index 901975fd120921b36dabf88e1d8d9c42a4803501..219f3ebe8e22876db4c98b30aa090c3091dbad4d 100644 (file)
@@ -205,6 +205,10 @@ static void init_pwm_of_config(struct pwm_chip *chip, struct pwm_device *pwm)
        if (!np)
                return;
 
+       ret = of_property_read_u32(np, "capture-window-length", &pval);
+       if (!ret)
+               pwm->capture_win_len = pval;
+
        ret = of_property_read_u32(np, "pwm-ramp-time", &pval);
        if (!ret)
                pwm->ramp_time = pval;
@@ -640,6 +644,57 @@ int pwm_set_double_pulse_period(struct pwm_device *pwm, int period)
 }
 EXPORT_SYMBOL_GPL(pwm_set_double_pulse_period);
 
+/**
+ * pwm_set_capture_window_length(): Set PWM capture window length.
+ * @pwm: PWM device
+ * @window_length: Window length.
+ *
+ * Window lenght to capture the PWM signal.
+ *
+ * Returns 0 in success else negative error number in failure.
+ */
+int pwm_set_capture_window_length(struct pwm_device *pwm, int window_length)
+{
+       int err;
+
+       if (!pwm || window_length <= 0)
+               return -EINVAL;
+
+       if (!pwm->chip->ops->set_capture_window_length)
+               return -ENOTSUPP;
+
+       err = pwm->chip->ops->set_capture_window_length(pwm->chip, pwm,
+                                                       window_length);
+       if (err)
+               return err;
+
+       pwm->capture_win_len = window_length;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pwm_set_capture_window_length);
+
+/**
+ * pwm_get_rpm(): Get PWM RPM.
+ * @pwm: PWM device
+ *
+ * Read PWM signal and return RPM value.
+ *
+ * Returns positive integer for valid RPM else negative error.
+ */
+int pwm_get_rpm(struct pwm_device *pwm)
+{
+       struct pwm_capture result;
+       int err;
+
+       err = pwm_capture(pwm, &result, 0);
+       if (err < 0)
+               return err;
+
+       return result.rpm;
+}
+EXPORT_SYMBOL_GPL(pwm_get_rpm);
+
 static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
 {
        struct pwm_chip *chip;
index 8a4131a6ff8260d27d8d34a483ec76ad1d159ed3..99ed022f6cf7186d9f06b7e6bb2b4cc05de2736b 100644 (file)
@@ -219,12 +219,49 @@ static ssize_t ramp_time_store(struct device *child,
        return ret ? : size;
 }
 
+static ssize_t capture_window_length_show(struct device *child,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       const struct pwm_device *pwm = child_to_pwm_device(child);
+
+       return sprintf(buf, "%u\n", pwm_get_capture_window_length(pwm));
+}
+
+static ssize_t capture_window_length_store(struct device *child,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t size)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+       unsigned int val;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       ret = pwm_set_capture_window_length(pwm, val);
+
+       return ret ? : size;
+}
+
+static ssize_t rpm_show(struct device *child,
+                       struct device_attribute *attr,
+                       char *buf)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+
+       return sprintf(buf, "%d\n", pwm_get_rpm(pwm));
+}
+
 static DEVICE_ATTR_RW(period);
 static DEVICE_ATTR_RW(duty_cycle);
 static DEVICE_ATTR_RW(enable);
 static DEVICE_ATTR_RW(polarity);
 static DEVICE_ATTR_RW(double_period);
 static DEVICE_ATTR_RW(ramp_time);
+static DEVICE_ATTR_RW(capture_window_length);
+static DEVICE_ATTR_RO(rpm);
 
 static struct attribute *pwm_attrs[] = {
        &dev_attr_period.attr,
@@ -233,6 +270,8 @@ static struct attribute *pwm_attrs[] = {
        &dev_attr_polarity.attr,
        &dev_attr_double_period.attr,
        &dev_attr_ramp_time.attr,
+       &dev_attr_capture_window_length.attr,
+       &dev_attr_rpm.attr,
        NULL
 };
 ATTRIBUTE_GROUPS(pwm);
index e6d930f4336428ae64098a3c693bcb3fa4746c5c..7cd161f3506c89bac004a290bd68edafb7ccf586 100644 (file)
@@ -44,6 +44,17 @@ int pwm_set_ramp_time(struct pwm_device *pwm, int ramp_time);
  * Set double pulse period.
  */
 int pwm_set_double_pulse_period(struct pwm_device *pwm, int period);
+
+/*
+ * Set PWM capture window length.
+ */
+int pwm_set_capture_window_length(struct pwm_device *pwm, int window_length);
+
+/*
+ * Get PWM RPM.
+ */
+int pwm_get_rpm(struct pwm_device *pwm);
+
 #else
 static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
 {
@@ -78,6 +89,17 @@ static inline int pwm_set_double_pulse_period(struct pwm_device *pwm,
 {
        return -EINVAL;
 }
+
+static inline int pwm_set_capture_window_length(struct pwm_device *pwm,
+                                              int window_length)
+{
+       return -EINVAL;
+}
+
+static inline int pwm_get_rpm(struct pwm_device *pwm)
+{
+       return -EINVAL;
+}
 #endif
 
 struct pwm_chip;
@@ -115,6 +137,7 @@ enum {
  * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
  * @double_period: Doble pulse period.
  * @ramp_time: Ramp up/down time.
+ * @capture_win_len: Window length for captureing PWM signal.
  * @polarity: polarity of the PWM signal
  */
 struct pwm_device {
@@ -131,6 +154,7 @@ struct pwm_device {
        enum pwm_polarity polarity;
        unsigned int double_period;
        unsigned int ramp_time;
+       unsigned int capture_win_len;;
 };
 
 static inline bool pwm_is_enabled(const struct pwm_device *pwm)
@@ -170,6 +194,12 @@ static inline unsigned int pwm_get_ramp_time(const struct pwm_device *pwm)
        return pwm ? pwm->ramp_time : 0;
 }
 
+static inline unsigned int pwm_get_capture_window_length(
+                                       const struct pwm_device *pwm)
+{
+       return pwm ? pwm->capture_win_len : 0;
+}
+
 /*
  * pwm_set_polarity - configure the polarity of a PWM signal
  */
@@ -191,6 +221,7 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
  * @disable: disable PWM output toggling
  * @set_ramp_time: Set PWM ramp up/down time.
  * @set_double_pulse_period: Set double pulse period time.
+ * @set_capture_window_length: Set PWM capture window length.
  * @dbg_show: optional routine to show contents in debugfs
  * @owner: helps prevent removal of modules exporting active PWMs
  */
@@ -210,6 +241,9 @@ struct pwm_ops {
        int (*set_double_pulse_period)(struct pwm_chip *chip,
                                       struct pwm_device *pwm,
                                       int period);
+       int (*set_capture_window_length)(struct pwm_chip *chip,
+                                        struct pwm_device *pwm,
+                                        int window_length);
 #ifdef CONFIG_DEBUG_FS
        void (*dbg_show)(struct pwm_chip *chip, struct seq_file *s);
 #endif
@@ -248,10 +282,12 @@ struct pwm_chip {
  * struct pwm_capture - PWM capture data
  * @period: period of the PWM signal (in nanoseconds)
  * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
+ * @rpm: Revolution per minute.
  */
 struct pwm_capture {
        unsigned int period;
        unsigned int duty_cycle;
+       unsigned int rpm;
 };
 
 #if IS_ENABLED(CONFIG_PWM)