Loading drivers/pwm/core.c +26 −0 Original line number Diff line number Diff line Loading @@ -294,6 +294,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, pwm->pwm = chip->base + i; pwm->hwpwm = i; pwm->state.polarity = polarity; pwm->state.output_type = PWM_OUTPUT_FIXED; if (chip->ops->get_state) chip->ops->get_state(chip, pwm, &pwm->state); Loading Loading @@ -507,6 +508,31 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) pwm->state.polarity = state->polarity; } if (state->output_type != pwm->state.output_type) { if (!pwm->chip->ops->set_output_type) return -ENOTSUPP; err = pwm->chip->ops->set_output_type(pwm->chip, pwm, state->output_type); if (err) return err; pwm->state.output_type = state->output_type; } if (state->output_pattern != pwm->state.output_pattern && state->output_pattern != NULL) { if (!pwm->chip->ops->set_output_pattern) return -ENOTSUPP; err = pwm->chip->ops->set_output_pattern(pwm->chip, pwm, state->output_pattern); if (err) return err; pwm->state.output_pattern = state->output_pattern; } if (state->period != pwm->state.period || state->duty_cycle != pwm->state.duty_cycle) { err = pwm->chip->ops->config(pwm->chip, pwm, Loading drivers/pwm/sysfs.c +50 −0 Original line number Diff line number Diff line Loading @@ -223,11 +223,60 @@ 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 ssize_t output_type_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { struct pwm_export *export = child_to_pwm_export(child); struct pwm_device *pwm = export->pwm; struct pwm_state state; int ret = -EINVAL; mutex_lock(&export->lock); pwm_get_state(pwm, &state); if (sysfs_streq(buf, "fixed")) state.output_type = PWM_OUTPUT_FIXED; else if (sysfs_streq(buf, "modulated")) state.output_type = PWM_OUTPUT_MODULATED; else goto unlock; ret = pwm_apply_state(pwm, &state); unlock: mutex_unlock(&export->lock); return ret ? : size; } 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_RW(output_type); static struct attribute *pwm_attrs[] = { &dev_attr_period.attr, Loading @@ -235,6 +284,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); Loading include/linux/pwm.h +70 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,29 @@ 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_output_pattern - PWM duty pattern for MODULATED duty type * @duty_pattern: PWM duty cycles in the pattern for duty modulation * @num_entries: number of entries in the pattern * @cycles_per_duty: number of PWM period cycles an entry stays at */ struct pwm_output_pattern { unsigned int *duty_pattern; unsigned int num_entries; unsigned int cycles_per_duty; }; /* * struct pwm_state - state of a PWM channel * @period: PWM period (in nanoseconds) Loading @@ -59,6 +82,8 @@ struct pwm_state { unsigned int period; unsigned int duty_cycle; enum pwm_polarity polarity; enum pwm_output_type output_type; struct pwm_output_pattern *output_pattern; bool enabled; }; Loading Loading @@ -144,6 +169,26 @@ 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 struct pwm_output_pattern *pwm_get_output_pattern( struct pwm_device *pwm) { struct pwm_state state; pwm_get_state(pwm, &state); return pwm->state.output_pattern ?: NULL; } static inline void pwm_get_args(const struct pwm_device *pwm, struct pwm_args *args) { Loading Loading @@ -247,6 +292,9 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle, * @capture: capture and report PWM signal * @enable: enable PWM output toggling * @disable: disable PWM output toggling * @get_output_type_supported: get the supported output type * @set_output_type: set PWM output type * @set_output_pattern: set the pattern for the modulated output * @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 Loading @@ -268,6 +316,13 @@ struct pwm_ops { 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 (*get_output_type_supported)(struct pwm_chip *chip, struct pwm_device *pwm); int (*set_output_type)(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_output_type output_type); int (*set_output_pattern)(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_output_pattern *output_pattern); 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, Loading Loading @@ -320,6 +375,21 @@ 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_output_type_support() * @pwm: PWM device * * Returns: output types supported by the PWM device */ static inline int pwm_get_output_type_supported(struct pwm_device *pwm) { if (pwm->chip->ops->get_output_type_supported != NULL) return pwm->chip->ops-> get_output_type_supported(pwm->chip, pwm); else return PWM_OUTPUT_FIXED; } /** * pwm_config() - change a PWM device configuration * @pwm: PWM device Loading Loading
drivers/pwm/core.c +26 −0 Original line number Diff line number Diff line Loading @@ -294,6 +294,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, pwm->pwm = chip->base + i; pwm->hwpwm = i; pwm->state.polarity = polarity; pwm->state.output_type = PWM_OUTPUT_FIXED; if (chip->ops->get_state) chip->ops->get_state(chip, pwm, &pwm->state); Loading Loading @@ -507,6 +508,31 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) pwm->state.polarity = state->polarity; } if (state->output_type != pwm->state.output_type) { if (!pwm->chip->ops->set_output_type) return -ENOTSUPP; err = pwm->chip->ops->set_output_type(pwm->chip, pwm, state->output_type); if (err) return err; pwm->state.output_type = state->output_type; } if (state->output_pattern != pwm->state.output_pattern && state->output_pattern != NULL) { if (!pwm->chip->ops->set_output_pattern) return -ENOTSUPP; err = pwm->chip->ops->set_output_pattern(pwm->chip, pwm, state->output_pattern); if (err) return err; pwm->state.output_pattern = state->output_pattern; } if (state->period != pwm->state.period || state->duty_cycle != pwm->state.duty_cycle) { err = pwm->chip->ops->config(pwm->chip, pwm, Loading
drivers/pwm/sysfs.c +50 −0 Original line number Diff line number Diff line Loading @@ -223,11 +223,60 @@ 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 ssize_t output_type_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { struct pwm_export *export = child_to_pwm_export(child); struct pwm_device *pwm = export->pwm; struct pwm_state state; int ret = -EINVAL; mutex_lock(&export->lock); pwm_get_state(pwm, &state); if (sysfs_streq(buf, "fixed")) state.output_type = PWM_OUTPUT_FIXED; else if (sysfs_streq(buf, "modulated")) state.output_type = PWM_OUTPUT_MODULATED; else goto unlock; ret = pwm_apply_state(pwm, &state); unlock: mutex_unlock(&export->lock); return ret ? : size; } 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_RW(output_type); static struct attribute *pwm_attrs[] = { &dev_attr_period.attr, Loading @@ -235,6 +284,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); Loading
include/linux/pwm.h +70 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,29 @@ 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_output_pattern - PWM duty pattern for MODULATED duty type * @duty_pattern: PWM duty cycles in the pattern for duty modulation * @num_entries: number of entries in the pattern * @cycles_per_duty: number of PWM period cycles an entry stays at */ struct pwm_output_pattern { unsigned int *duty_pattern; unsigned int num_entries; unsigned int cycles_per_duty; }; /* * struct pwm_state - state of a PWM channel * @period: PWM period (in nanoseconds) Loading @@ -59,6 +82,8 @@ struct pwm_state { unsigned int period; unsigned int duty_cycle; enum pwm_polarity polarity; enum pwm_output_type output_type; struct pwm_output_pattern *output_pattern; bool enabled; }; Loading Loading @@ -144,6 +169,26 @@ 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 struct pwm_output_pattern *pwm_get_output_pattern( struct pwm_device *pwm) { struct pwm_state state; pwm_get_state(pwm, &state); return pwm->state.output_pattern ?: NULL; } static inline void pwm_get_args(const struct pwm_device *pwm, struct pwm_args *args) { Loading Loading @@ -247,6 +292,9 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle, * @capture: capture and report PWM signal * @enable: enable PWM output toggling * @disable: disable PWM output toggling * @get_output_type_supported: get the supported output type * @set_output_type: set PWM output type * @set_output_pattern: set the pattern for the modulated output * @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 Loading @@ -268,6 +316,13 @@ struct pwm_ops { 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 (*get_output_type_supported)(struct pwm_chip *chip, struct pwm_device *pwm); int (*set_output_type)(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_output_type output_type); int (*set_output_pattern)(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_output_pattern *output_pattern); 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, Loading Loading @@ -320,6 +375,21 @@ 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_output_type_support() * @pwm: PWM device * * Returns: output types supported by the PWM device */ static inline int pwm_get_output_type_supported(struct pwm_device *pwm) { if (pwm->chip->ops->get_output_type_supported != NULL) return pwm->chip->ops-> get_output_type_supported(pwm->chip, pwm); else return PWM_OUTPUT_FIXED; } /** * pwm_config() - change a PWM device configuration * @pwm: PWM device Loading