]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pwm: adp5585: add support for adp5589
authorNuno Sá <nuno.sa@analog.com>
Tue, 1 Jul 2025 14:32:05 +0000 (15:32 +0100)
committerLee Jones <lee@kernel.org>
Tue, 1 Jul 2025 20:50:51 +0000 (21:50 +0100)
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: Uwe Kleine-König <ukleinek@kernel.org>
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20250701-dev-adp5589-fw-v7-10-b1fcfe9e9826@analog.com
Signed-off-by: Lee Jones <lee@kernel.org>
drivers/pwm/pwm-adp5585.c
include/linux/mfd/adp5585.h

index add36bc7d2216c9f06cb8801192b10318c748186..dc2860979e24e8644bb8c0f2078330b4315e0a6e 100644 (file)
 #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);
index d26f722cf31af5416eefecab5e542e66b01321f6..77f7c74f084dde01e11816fb7ed099721b6ed78d 100644 (file)
 #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