Commit 75024f97 authored by Nuno Sá's avatar Nuno Sá Committed by Lee Jones
Browse files

pwm: adp5585: add support for adp5589



Add support for the adp5589 I/O expander. From a PWM point of view it is
pretty similar to adp5585. Main difference is the address
of registers meaningful for configuring the PWM.

Acked-by: default avatarUwe Kleine-König <ukleinek@kernel.org>
Signed-off-by: default avatarNuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20250701-dev-adp5589-fw-v7-10-b1fcfe9e9826@analog.com


Signed-off-by: default avatarLee Jones <lee@kernel.org>
parent 9f425bf7
Loading
Loading
Loading
Loading
+56 −17
Original line number Diff line number Diff line
@@ -33,21 +33,33 @@
#define ADP5585_PWM_MIN_PERIOD_NS	(2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
#define ADP5585_PWM_MAX_PERIOD_NS	(2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)

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 regmap *regmap = pwmchip_get_drvdata(chip);
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);

	/* Configure the R3 pin as PWM output. */
	return regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C,
	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 regmap *regmap = pwmchip_get_drvdata(chip);
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);

	regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C,
	regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
			   ADP5585_R3_EXTEND_CFG_MASK,
			   ADP5585_R3_EXTEND_CFG_GPIO4);
}
@@ -56,14 +68,16 @@ static int pwm_adp5585_apply(struct pwm_chip *chip,
			     struct pwm_device *pwm,
			     const struct pwm_state *state)
{
	struct regmap *regmap = pwmchip_get_drvdata(chip);
	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, ADP5585_PWM_CFG, ADP5585_PWM_EN);
		regmap_clear_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
		return 0;
	}

@@ -84,41 +98,43 @@ static int pwm_adp5585_apply(struct pwm_chip *chip,
	off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on;

	val = cpu_to_le16(off);
	ret = regmap_bulk_write(regmap, ADP5585_PWM_OFFT_LOW, &val, 2);
	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, ADP5585_PWM_ONT_LOW, &val, 2);
	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, ADP5585_PWM_CFG,
	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, ADP5585_PWM_CFG, ADP5585_PWM_EN);
	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 regmap *regmap = pwmchip_get_drvdata(chip);
	struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
	const struct adp5585_pwm_chip *info = adp5585_pwm->info;
	struct regmap *regmap = adp5585_pwm->regmap;
	unsigned int on, off;
	unsigned int val;
	__le16 on_off;
	int ret;

	ret = regmap_bulk_read(regmap, ADP5585_PWM_OFFT_LOW, &on_off, 2);
	ret = regmap_bulk_read(regmap, info->pwm_offt_low, &on_off, 2);
	if (ret)
		return ret;
	off = le16_to_cpu(on_off);

	ret = regmap_bulk_read(regmap, ADP5585_PWM_ONT_LOW, &on_off, 2);
	ret = regmap_bulk_read(regmap, info->pwm_ont_low, &on_off, 2);
	if (ret)
		return ret;
	on = le16_to_cpu(on_off);
@@ -128,7 +144,7 @@ static int pwm_adp5585_get_state(struct pwm_chip *chip,

	state->polarity = PWM_POLARITY_NORMAL;

	regmap_read(regmap, ADP5585_PWM_CFG, &val);
	regmap_read(regmap, info->pwm_cfg, &val);
	state->enabled = !!(val & ADP5585_PWM_EN);

	return 0;
@@ -143,18 +159,28 @@ static const struct pwm_ops adp5585_pwm_ops = {

static int adp5585_pwm_probe(struct platform_device *pdev)
{
	const struct platform_device_id *id = platform_get_device_id(pdev);
	struct device *dev = &pdev->dev;
	struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
	struct adp5585_pwm *adp5585_pwm;
	struct pwm_chip *chip;
	int ret;

	chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM, 0);
	chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM,
				  sizeof(*adp5585_pwm));
	if (IS_ERR(chip))
		return PTR_ERR(chip);

	adp5585_pwm = pwmchip_get_drvdata(chip);
	adp5585_pwm->regmap = adp5585->regmap;
	adp5585_pwm->ext_cfg = adp5585->regs->ext_cfg;

	adp5585_pwm->info = (const struct adp5585_pwm_chip *)id->driver_data;
	if (!adp5585_pwm->info)
		return -ENODEV;

	device_set_of_node_from_dev(dev, dev->parent);

	pwmchip_set_drvdata(chip, adp5585->regmap);
	chip->ops = &adp5585_pwm_ops;

	ret = devm_pwmchip_add(dev, chip);
@@ -164,8 +190,21 @@ static int adp5585_pwm_probe(struct platform_device *pdev)
	return 0;
}

static const struct adp5585_pwm_chip adp5589_pwm_chip_info = {
	.pwm_cfg = ADP5585_PWM_CFG,
	.pwm_offt_low = ADP5585_PWM_OFFT_LOW,
	.pwm_ont_low = ADP5585_PWM_ONT_LOW,
};

static const struct adp5585_pwm_chip adp5585_pwm_chip_info = {
	.pwm_cfg = ADP5589_PWM_CFG,
	.pwm_offt_low = ADP5589_PWM_OFFT_LOW,
	.pwm_ont_low = ADP5589_PWM_ONT_LOW,
};

static const struct platform_device_id adp5585_pwm_id_table[] = {
	{ "adp5585-pwm" },
	{ "adp5585-pwm", (kernel_ulong_t)&adp5585_pwm_chip_info },
	{ "adp5589-pwm", (kernel_ulong_t)&adp5589_pwm_chip_info },
	{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(platform, adp5585_pwm_id_table);
+3 −0
Original line number Diff line number Diff line
@@ -118,6 +118,9 @@
#define ADP5589_GPO_DATA_OUT_A		0x2a
#define ADP5589_GPO_OUT_MODE_A		0x2d
#define		ADP5589_GPIO_DIRECTION_A	0x30
#define ADP5589_PWM_OFFT_LOW		0x3e
#define ADP5589_PWM_ONT_LOW		0x40
#define ADP5589_PWM_CFG			0x42
#define ADP5589_PIN_CONFIG_D		0x4C
#define ADP5589_INT_EN			0x4e
#define ADP5589_MAX_REG			ADP5589_INT_EN