drivers/pwm/pwm-adp5585.c

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

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-adp5585.c
Extension
.c
Size
6224 bytes
Lines
224
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 adp5585_pwm_chip {
	unsigned int pwm_cfg;
	unsigned int pwm_offt_low;
	unsigned int pwm_ont_low;
};

struct adp5585_pwm {
	const struct adp5585_pwm_chip *info;
	struct regmap *regmap;
	unsigned int ext_cfg;
};

static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);

	/* Configure the R3 pin as PWM output. */
	return regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
				  ADP5585_R3_EXTEND_CFG_MASK,
				  ADP5585_R3_EXTEND_CFG_PWM_OUT);
}

static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);

	regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
			   ADP5585_R3_EXTEND_CFG_MASK,
			   ADP5585_R3_EXTEND_CFG_GPIO4);
}

static int pwm_adp5585_apply(struct pwm_chip *chip,
			     struct pwm_device *pwm,
			     const struct pwm_state *state)
{
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
	const struct adp5585_pwm_chip *info = adp5585_pwm->info;
	struct regmap *regmap = adp5585_pwm->regmap;
	u64 period, duty_cycle;
	u32 on, off;
	__le16 val;
	int ret;

	if (!state->enabled) {
		regmap_clear_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
		return 0;
	}

	if (state->polarity != PWM_POLARITY_NORMAL)
		return -EINVAL;

	if (state->period < ADP5585_PWM_MIN_PERIOD_NS)
		return -EINVAL;

	period = min(state->period, ADP5585_PWM_MAX_PERIOD_NS);
	duty_cycle = min(state->duty_cycle, period);

	/*
	 * Compute the on and off time. As the internal oscillator frequency is
	 * 1MHz, the calculation can be simplified without loss of precision.
	 */
	on = div_u64(duty_cycle, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ);
	off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on;

	val = cpu_to_le16(off);
	ret = regmap_bulk_write(regmap, info->pwm_offt_low, &val, 2);
	if (ret)
		return ret;

	val = cpu_to_le16(on);
	ret = regmap_bulk_write(regmap, info->pwm_ont_low, &val, 2);
	if (ret)
		return ret;

	/* Enable PWM in continuous mode and no external AND'ing. */
	ret = regmap_update_bits(regmap, info->pwm_cfg,
				 ADP5585_PWM_IN_AND | ADP5585_PWM_MODE |
				 ADP5585_PWM_EN, ADP5585_PWM_EN);
	if (ret)
		return ret;

	return regmap_set_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
}

static int pwm_adp5585_get_state(struct pwm_chip *chip,
				 struct pwm_device *pwm,
				 struct pwm_state *state)
{
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
	const struct adp5585_pwm_chip *info = adp5585_pwm->info;

Annotation

Implementation Notes