fiq_debugger: merge from linux 3.10
[firefly-linux-kernel-4.4.55.git] / include / linux / pwm.h
index cfc3ed46cad20a26ffa131b51e25927ac6045f4c..2c6c5114c089456cf0d3bac380a922132b077b7d 100644 (file)
@@ -5,59 +5,9 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 
-struct pwm_device;
+struct pwm_capture;
 struct seq_file;
 
-#if IS_ENABLED(CONFIG_PWM)
-/*
- * pwm_request - request a PWM device
- */
-struct pwm_device *pwm_request(int pwm_id, const char *label);
-
-/*
- * pwm_free - free a PWM device
- */
-void pwm_free(struct pwm_device *pwm);
-
-/*
- * pwm_config - change a PWM device configuration
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
-
-/*
- * pwm_enable - start a PWM output toggling
- */
-int pwm_enable(struct pwm_device *pwm);
-
-/*
- * pwm_disable - stop a PWM output toggling
- */
-void pwm_disable(struct pwm_device *pwm);
-#else
-static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline void pwm_free(struct pwm_device *pwm)
-{
-}
-
-static inline int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       return -EINVAL;
-}
-
-static inline int pwm_enable(struct pwm_device *pwm)
-{
-       return -EINVAL;
-}
-
-static inline void pwm_disable(struct pwm_device *pwm)
-{
-}
-#endif
-
 struct pwm_chip;
 
 /**
@@ -74,10 +24,41 @@ enum pwm_polarity {
        PWM_POLARITY_INVERSED,
 };
 
+/**
+ * struct pwm_args - board-dependent PWM arguments
+ * @period: reference period
+ * @polarity: reference polarity
+ *
+ * This structure describes board-dependent arguments attached to a PWM
+ * device. These arguments are usually retrieved from the PWM lookup table or
+ * device tree.
+ *
+ * Do not confuse this with the PWM state: PWM arguments represent the initial
+ * configuration that users want to use on this PWM device rather than the
+ * current PWM hardware state.
+ */
+struct pwm_args {
+       unsigned int period;
+       enum pwm_polarity polarity;
+};
+
 enum {
        PWMF_REQUESTED = 1 << 0,
-       PWMF_ENABLED = 1 << 1,
-       PWMF_EXPORTED = 1 << 2,
+       PWMF_EXPORTED = 1 << 1,
+};
+
+/*
+ * struct pwm_state - state of a PWM channel
+ * @period: PWM period (in nanoseconds)
+ * @duty_cycle: PWM duty cycle (in nanoseconds)
+ * @polarity: PWM polarity
+ * @enabled: PWM enabled status
+ */
+struct pwm_state {
+       unsigned int period;
+       unsigned int duty_cycle;
+       enum pwm_polarity polarity;
+       bool enabled;
 };
 
 /**
@@ -88,10 +69,8 @@ enum {
  * @pwm: global index of the PWM device
  * @chip: PWM chip providing this PWM device
  * @chip_data: chip-private data associated with the PWM device
- * @lock: used to serialize accesses to the PWM device where necessary
- * @period: period of the PWM signal (in nanoseconds)
- * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
- * @polarity: polarity of the PWM signal
+ * @args: PWM arguments
+ * @state: curent PWM channel state
  */
 struct pwm_device {
        const char *label;
@@ -100,48 +79,162 @@ struct pwm_device {
        unsigned int pwm;
        struct pwm_chip *chip;
        void *chip_data;
-       struct mutex lock;
 
-       unsigned int period;
-       unsigned int duty_cycle;
-       enum pwm_polarity polarity;
+       struct pwm_args args;
+       struct pwm_state state;
 };
 
+/**
+ * pwm_get_state() - retrieve the current PWM state
+ * @pwm: PWM device
+ * @state: state to fill with the current PWM state
+ */
+static inline void pwm_get_state(const struct pwm_device *pwm,
+                                struct pwm_state *state)
+{
+       *state = pwm->state;
+}
+
 static inline bool pwm_is_enabled(const struct pwm_device *pwm)
 {
-       return test_bit(PWMF_ENABLED, &pwm->flags);
+       struct pwm_state state;
+
+       pwm_get_state(pwm, &state);
+
+       return state.enabled;
 }
 
 static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
 {
        if (pwm)
-               pwm->period = period;
+               pwm->state.period = period;
 }
 
 static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
 {
-       return pwm ? pwm->period : 0;
+       struct pwm_state state;
+
+       pwm_get_state(pwm, &state);
+
+       return state.period;
 }
 
 static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
 {
        if (pwm)
-               pwm->duty_cycle = duty;
+               pwm->state.duty_cycle = duty;
 }
 
 static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
 {
-       return pwm ? pwm->duty_cycle : 0;
+       struct pwm_state state;
+
+       pwm_get_state(pwm, &state);
+
+       return state.duty_cycle;
 }
 
-/*
- * pwm_set_polarity - configure the polarity of a PWM signal
+static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
+{
+       struct pwm_state state;
+
+       pwm_get_state(pwm, &state);
+
+       return state.polarity;
+}
+
+static inline void pwm_get_args(const struct pwm_device *pwm,
+                               struct pwm_args *args)
+{
+       *args = pwm->args;
+}
+
+/**
+ * pwm_init_state() - prepare a new state to be applied with pwm_apply_state()
+ * @pwm: PWM device
+ * @state: state to fill with the prepared PWM state
+ *
+ * This functions prepares a state that can later be tweaked and applied
+ * to the PWM device with pwm_apply_state(). This is a convenient function
+ * that first retrieves the current PWM state and the replaces the period
+ * and polarity fields with the reference values defined in pwm->args.
+ * Once the function returns, you can adjust the ->enabled and ->duty_cycle
+ * fields according to your needs before calling pwm_apply_state().
+ *
+ * ->duty_cycle is initially set to zero to avoid cases where the current
+ * ->duty_cycle value exceed the pwm_args->period one, which would trigger
+ * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle
+ * first.
  */
-int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
+static inline void pwm_init_state(const struct pwm_device *pwm,
+                                 struct pwm_state *state)
+{
+       struct pwm_args args;
 
-static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
+       /* First get the current state. */
+       pwm_get_state(pwm, state);
+
+       /* Then fill it with the reference config */
+       pwm_get_args(pwm, &args);
+
+       state->period = args.period;
+       state->polarity = args.polarity;
+       state->duty_cycle = 0;
+}
+
+/**
+ * pwm_get_relative_duty_cycle() - Get a relative duty cycle value
+ * @state: PWM state to extract the duty cycle from
+ * @scale: target scale of the relative duty cycle
+ *
+ * This functions converts the absolute duty cycle stored in @state (expressed
+ * in nanosecond) into a value relative to the period.
+ *
+ * For example if you want to get the duty_cycle expressed in percent, call:
+ *
+ * pwm_get_state(pwm, &state);
+ * duty = pwm_get_relative_duty_cycle(&state, 100);
+ */
+static inline unsigned int
+pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale)
 {
-       return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
+       if (!state->period)
+               return 0;
+
+       return DIV_ROUND_CLOSEST_ULL((u64)state->duty_cycle * scale,
+                                    state->period);
+}
+
+/**
+ * pwm_set_relative_duty_cycle() - Set a relative duty cycle value
+ * @state: PWM state to fill
+ * @duty_cycle: relative duty cycle value
+ * @scale: scale in which @duty_cycle is expressed
+ *
+ * This functions converts a relative into an absolute duty cycle (expressed
+ * in nanoseconds), and puts the result in state->duty_cycle.
+ *
+ * For example if you want to configure a 50% duty cycle, call:
+ *
+ * pwm_init_state(pwm, &state);
+ * pwm_set_relative_duty_cycle(&state, 50, 100);
+ * pwm_apply_state(pwm, &state);
+ *
+ * This functions returns -EINVAL if @duty_cycle and/or @scale are
+ * inconsistent (@scale == 0 or @duty_cycle > @scale).
+ */
+static inline int
+pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
+                           unsigned int scale)
+{
+       if (!scale || duty_cycle > scale)
+               return -EINVAL;
+
+       state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_cycle *
+                                                 state->period,
+                                                 scale);
+
+       return 0;
 }
 
 /**
@@ -150,8 +243,16 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
  * @free: optional hook for freeing a PWM
  * @config: configure duty cycles and period length for this PWM
  * @set_polarity: configure the polarity of this PWM
+ * @capture: capture and report PWM signal
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
+ * @apply: atomically apply a new PWM config. The state argument
+ *        should be adjusted with the real hardware config (if the
+ *        approximate the period or duty_cycle value, state should
+ *        reflect it)
+ * @get_state: get the current PWM state. This function is only
+ *            called once per PWM device when the PWM chip is
+ *            registered.
  * @dbg_show: optional routine to show contents in debugfs
  * @owner: helps prevent removal of modules exporting active PWMs
  */
@@ -162,8 +263,14 @@ struct pwm_ops {
                      int duty_ns, int period_ns);
        int (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm,
                            enum pwm_polarity polarity);
+       int (*capture)(struct pwm_chip *chip, struct pwm_device *pwm,
+                      struct pwm_capture *result, unsigned long timeout);
        int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm);
        void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm);
+       int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm,
+                    struct pwm_state *state);
+       void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
+                         struct pwm_state *state);
 #ifdef CONFIG_DEBUG_FS
        void (*dbg_show)(struct pwm_chip *chip, struct seq_file *s);
 #endif
@@ -198,7 +305,130 @@ struct pwm_chip {
        bool can_sleep;
 };
 
+/**
+ * struct pwm_capture - PWM capture data
+ * @period: period of the PWM signal (in nanoseconds)
+ * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
+ */
+struct pwm_capture {
+       unsigned int period;
+       unsigned int duty_cycle;
+};
+
 #if IS_ENABLED(CONFIG_PWM)
+/* PWM user APIs */
+struct pwm_device *pwm_request(int pwm_id, const char *label);
+void pwm_free(struct pwm_device *pwm);
+int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
+int pwm_adjust_config(struct pwm_device *pwm);
+
+/**
+ * pwm_config() - change a PWM device configuration
+ * @pwm: PWM device
+ * @duty_ns: "on" time (in nanoseconds)
+ * @period_ns: duration (in nanoseconds) of one cycle
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
+                            int period_ns)
+{
+       struct pwm_state state;
+
+       if (!pwm)
+               return -EINVAL;
+
+       if (duty_ns < 0 || period_ns < 0)
+               return -EINVAL;
+
+       pwm_get_state(pwm, &state);
+       if (state.duty_cycle == duty_ns && state.period == period_ns)
+               return 0;
+
+       state.duty_cycle = duty_ns;
+       state.period = period_ns;
+       return pwm_apply_state(pwm, &state);
+}
+
+/**
+ * pwm_set_polarity() - configure the polarity of a PWM signal
+ * @pwm: PWM device
+ * @polarity: new polarity of the PWM signal
+ *
+ * Note that the polarity cannot be configured while the PWM device is
+ * enabled.
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int pwm_set_polarity(struct pwm_device *pwm,
+                                  enum pwm_polarity polarity)
+{
+       struct pwm_state state;
+
+       if (!pwm)
+               return -EINVAL;
+
+       pwm_get_state(pwm, &state);
+       if (state.polarity == polarity)
+               return 0;
+
+       /*
+        * Changing the polarity of a running PWM without adjusting the
+        * dutycycle/period value is a bit risky (can introduce glitches).
+        * Return -EBUSY in this case.
+        * Note that this is allowed when using pwm_apply_state() because
+        * the user specifies all the parameters.
+        */
+       if (state.enabled)
+               return -EBUSY;
+
+       state.polarity = polarity;
+       return pwm_apply_state(pwm, &state);
+}
+
+/**
+ * pwm_enable() - start a PWM output toggling
+ * @pwm: PWM device
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int pwm_enable(struct pwm_device *pwm)
+{
+       struct pwm_state state;
+
+       if (!pwm)
+               return -EINVAL;
+
+       pwm_get_state(pwm, &state);
+       if (state.enabled)
+               return 0;
+
+       state.enabled = true;
+       return pwm_apply_state(pwm, &state);
+}
+
+/**
+ * pwm_disable() - stop a PWM output toggling
+ * @pwm: PWM device
+ */
+static inline void pwm_disable(struct pwm_device *pwm)
+{
+       struct pwm_state state;
+
+       if (!pwm)
+               return;
+
+       pwm_get_state(pwm, &state);
+       if (!state.enabled)
+               return;
+
+       state.enabled = false;
+       pwm_apply_state(pwm, &state);
+}
+
+/* PWM provider APIs */
+int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
+               unsigned long timeout);
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);
 void *pwm_get_chip_data(struct pwm_device *pwm);
 
@@ -224,6 +454,54 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
 
 bool pwm_can_sleep(struct pwm_device *pwm);
 #else
+static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void pwm_free(struct pwm_device *pwm)
+{
+}
+
+static inline int pwm_apply_state(struct pwm_device *pwm,
+                                 const struct pwm_state *state)
+{
+       return -ENOTSUPP;
+}
+
+static inline int pwm_adjust_config(struct pwm_device *pwm)
+{
+       return -ENOTSUPP;
+}
+
+static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
+                            int period_ns)
+{
+       return -EINVAL;
+}
+
+static inline int pwm_capture(struct pwm_device *pwm,
+                             struct pwm_capture *result,
+                             unsigned long timeout)
+{
+       return -EINVAL;
+}
+
+static inline int pwm_set_polarity(struct pwm_device *pwm,
+                                  enum pwm_polarity polarity)
+{
+       return -ENOTSUPP;
+}
+
+static inline int pwm_enable(struct pwm_device *pwm)
+{
+       return -EINVAL;
+}
+
+static inline void pwm_disable(struct pwm_device *pwm)
+{
+}
+
 static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
 {
        return -EINVAL;
@@ -295,6 +573,38 @@ static inline bool pwm_can_sleep(struct pwm_device *pwm)
 }
 #endif
 
+static inline void pwm_apply_args(struct pwm_device *pwm)
+{
+       struct pwm_state state = { };
+
+       /*
+        * PWM users calling pwm_apply_args() expect to have a fresh config
+        * where the polarity and period are set according to pwm_args info.
+        * The problem is, polarity can only be changed when the PWM is
+        * disabled.
+        *
+        * PWM drivers supporting hardware readout may declare the PWM device
+        * as enabled, and prevent polarity setting, which changes from the
+        * existing behavior, where all PWM devices are declared as disabled
+        * at startup (even if they are actually enabled), thus authorizing
+        * polarity setting.
+        *
+        * To fulfill this requirement, we apply a new state which disables
+        * the PWM device and set the reference period and polarity config.
+        *
+        * Note that PWM users requiring a smooth handover between the
+        * bootloader and the kernel (like critical regulators controlled by
+        * PWM devices) will have to switch to the atomic API and avoid calling
+        * pwm_apply_args().
+        */
+
+       state.enabled = false;
+       state.polarity = pwm->args.polarity;
+       state.period = pwm->args.period;
+
+       pwm_apply_state(pwm, &state);
+}
+
 struct pwm_lookup {
        struct list_head list;
        const char *provider;
@@ -331,6 +641,7 @@ static inline void pwm_remove_table(struct pwm_lookup *table, size_t num)
 #ifdef CONFIG_PWM_SYSFS
 void pwmchip_sysfs_export(struct pwm_chip *chip);
 void pwmchip_sysfs_unexport(struct pwm_chip *chip);
+void pwmchip_sysfs_unexport_children(struct pwm_chip *chip);
 #else
 static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
 {
@@ -339,6 +650,10 @@ static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
 static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
 {
 }
+
+static inline void pwmchip_sysfs_unexport_children(struct pwm_chip *chip)
+{
+}
 #endif /* CONFIG_PWM_SYSFS */
 
 #endif /* __LINUX_PWM_H */