Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b08d78a1 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "pwm: Add different PWM output types support"

parents 78e2a700 51d5b4b8
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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,
+50 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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);
+70 −0
Original line number Diff line number Diff line
@@ -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)
@@ -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;
};

@@ -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)
{
@@ -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
@@ -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,
@@ -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