drivers/pwm/pwm-pca9685.c

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

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-pca9685.c
Extension
.c
Size
15691 bytes
Lines
580
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 pca9685 {
	struct regmap *regmap;
	struct mutex lock;
	DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1);
};

static inline struct pca9685 *to_pca(struct pwm_chip *chip)
{
	return pwmchip_get_drvdata(chip);
}

/* This function is supposed to be called with the lock mutex held */
static bool pca9685_prescaler_can_change(struct pca9685 *pca, int channel)
{
	/* No PWM enabled: Change allowed */
	if (bitmap_empty(pca->pwms_enabled, PCA9685_MAXCHAN + 1))
		return true;
	/* More than one PWM enabled: Change not allowed */
	if (bitmap_weight(pca->pwms_enabled, PCA9685_MAXCHAN + 1) > 1)
		return false;
	/*
	 * Only one PWM enabled: Change allowed if the PWM about to
	 * be changed is the one that is already enabled
	 */
	return test_bit(channel, pca->pwms_enabled);
}

static int pca9685_read_reg(struct pwm_chip *chip, unsigned int reg, unsigned int *val)
{
	struct pca9685 *pca = to_pca(chip);
	struct device *dev = pwmchip_parent(chip);
	int err;

	err = regmap_read(pca->regmap, reg, val);
	if (err)
		dev_err(dev, "regmap_read of register 0x%x failed: %pe\n", reg, ERR_PTR(err));

	return err;
}

static int pca9685_write_reg(struct pwm_chip *chip, unsigned int reg, unsigned int val)
{
	struct pca9685 *pca = to_pca(chip);
	struct device *dev = pwmchip_parent(chip);
	int err;

	err = regmap_write(pca->regmap, reg, val);
	if (err)
		dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err));

	return err;
}

static int pca9685_write_4reg(struct pwm_chip *chip, unsigned int reg, u8 val[4])
{
	struct pca9685 *pca = to_pca(chip);
	struct device *dev = pwmchip_parent(chip);
	int err;

	err = regmap_bulk_write(pca->regmap, reg, val, 4);
	if (err)
		dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err));

	return err;
}

static int pca9685_set_sleep_mode(struct pwm_chip *chip, bool enable)
{
	struct pca9685 *pca = to_pca(chip);
	int err;

	err = regmap_update_bits(pca->regmap, PCA9685_MODE1,
				 MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
	if (err)
		return err;

	if (!enable) {
		/* Wait 500us for the oscillator to be back up */
		udelay(500);
	}

	return 0;
}

struct pca9685_waveform {
	u8 onoff[4];
	u8 prescale;
};

static int pca9685_round_waveform_tohw(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_waveform *wf, void *_wfhw)

Annotation

Implementation Notes