drivers/pwm/pwm-max7360.c

Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-max7360.c

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-max7360.c
Extension
.c
Size
5932 bytes
Lines
211
Domain
Driver Families
Bucket
drivers/pwm
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct max7360_pwm_waveform {
	u8 duty_steps;
	bool enabled;
};

static int max7360_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct regmap *regmap = pwmchip_get_drvdata(chip);

	/*
	 * Make sure we use the individual PWM configuration register and not
	 * the global one.
	 * We never need to use the global one, so there is no need to revert
	 * that in the .free() callback.
	 */
	return regmap_write_bits(regmap, MAX7360_REG_PWMCFG(pwm->hwpwm),
				 MAX7360_PORT_CFG_COMMON_PWM, 0);
}

static int max7360_pwm_round_waveform_tohw(struct pwm_chip *chip,
					   struct pwm_device *pwm,
					   const struct pwm_waveform *wf,
					   void *_wfhw)
{
	struct max7360_pwm_waveform *wfhw = _wfhw;
	u64 duty_steps;

	/*
	 * Ignore user provided values for period_length_ns and duty_offset_ns:
	 * we only support fixed period of MAX7360_PWM_PERIOD_NS and offset of 0.
	 * Values from 0 to 254 as duty_steps will provide duty cycles of 0/256
	 * to 254/256, while value 255 will provide a duty cycle of 100%.
	 */
	if (wf->duty_length_ns >= MAX7360_PWM_PERIOD_NS) {
		duty_steps = MAX7360_PWM_MAX;
	} else {
		duty_steps = (u32)wf->duty_length_ns * MAX7360_PWM_STEPS / MAX7360_PWM_PERIOD_NS;
		if (duty_steps == MAX7360_PWM_MAX)
			duty_steps = MAX7360_PWM_MAX - 1;
	}

	wfhw->duty_steps = duty_steps;
	wfhw->enabled = !!wf->period_length_ns;

	if (wf->period_length_ns && wf->period_length_ns < MAX7360_PWM_PERIOD_NS)
		return 1;
	else
		return 0;
}

static int max7360_pwm_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm,
					     const void *_wfhw, struct pwm_waveform *wf)
{
	const struct max7360_pwm_waveform *wfhw = _wfhw;

	wf->period_length_ns = wfhw->enabled ? MAX7360_PWM_PERIOD_NS : 0;
	wf->duty_offset_ns = 0;

	if (wfhw->enabled) {
		if (wfhw->duty_steps == MAX7360_PWM_MAX)
			wf->duty_length_ns = MAX7360_PWM_PERIOD_NS;
		else
			wf->duty_length_ns = DIV_ROUND_UP(wfhw->duty_steps * MAX7360_PWM_PERIOD_NS,
							  MAX7360_PWM_STEPS);
	} else {
		wf->duty_length_ns = 0;
	}

	return 0;
}

static int max7360_pwm_write_waveform(struct pwm_chip *chip,
				      struct pwm_device *pwm,
				      const void *_wfhw)
{
	struct regmap *regmap = pwmchip_get_drvdata(chip);
	const struct max7360_pwm_waveform *wfhw = _wfhw;
	unsigned int val;
	int ret;

	if (wfhw->enabled) {
		ret = regmap_write(regmap, MAX7360_REG_PWM(pwm->hwpwm), wfhw->duty_steps);
		if (ret)
			return ret;
	}

	val = wfhw->enabled ? BIT(pwm->hwpwm) : 0;
	return regmap_write_bits(regmap, MAX7360_REG_GPIOCTRL, BIT(pwm->hwpwm), val);
}

Annotation

Implementation Notes