Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 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>

authored by

Nuno Sá and committed by
Lee Jones
75024f97 9f425bf7

+59 -17
+56 -17
drivers/pwm/pwm-adp5585.c
··· 33 33 #define ADP5585_PWM_MIN_PERIOD_NS (2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) 34 34 #define ADP5585_PWM_MAX_PERIOD_NS (2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) 35 35 36 + struct adp5585_pwm_chip { 37 + unsigned int pwm_cfg; 38 + unsigned int pwm_offt_low; 39 + unsigned int pwm_ont_low; 40 + }; 41 + 42 + struct adp5585_pwm { 43 + const struct adp5585_pwm_chip *info; 44 + struct regmap *regmap; 45 + unsigned int ext_cfg; 46 + }; 47 + 36 48 static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm) 37 49 { 38 - struct regmap *regmap = pwmchip_get_drvdata(chip); 50 + struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip); 39 51 40 52 /* Configure the R3 pin as PWM output. */ 41 - return regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C, 53 + return regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg, 42 54 ADP5585_R3_EXTEND_CFG_MASK, 43 55 ADP5585_R3_EXTEND_CFG_PWM_OUT); 44 56 } 45 57 46 58 static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm) 47 59 { 48 - struct regmap *regmap = pwmchip_get_drvdata(chip); 60 + struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip); 49 61 50 - regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C, 62 + regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg, 51 63 ADP5585_R3_EXTEND_CFG_MASK, 52 64 ADP5585_R3_EXTEND_CFG_GPIO4); 53 65 } ··· 68 56 struct pwm_device *pwm, 69 57 const struct pwm_state *state) 70 58 { 71 - struct regmap *regmap = pwmchip_get_drvdata(chip); 59 + struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip); 60 + const struct adp5585_pwm_chip *info = adp5585_pwm->info; 61 + struct regmap *regmap = adp5585_pwm->regmap; 72 62 u64 period, duty_cycle; 73 63 u32 on, off; 74 64 __le16 val; 75 65 int ret; 76 66 77 67 if (!state->enabled) { 78 - regmap_clear_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN); 68 + regmap_clear_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN); 79 69 return 0; 80 70 } 81 71 ··· 98 84 off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on; 99 85 100 86 val = cpu_to_le16(off); 101 - ret = regmap_bulk_write(regmap, ADP5585_PWM_OFFT_LOW, &val, 2); 87 + ret = regmap_bulk_write(regmap, info->pwm_offt_low, &val, 2); 102 88 if (ret) 103 89 return ret; 104 90 105 91 val = cpu_to_le16(on); 106 - ret = regmap_bulk_write(regmap, ADP5585_PWM_ONT_LOW, &val, 2); 92 + ret = regmap_bulk_write(regmap, info->pwm_ont_low, &val, 2); 107 93 if (ret) 108 94 return ret; 109 95 110 96 /* Enable PWM in continuous mode and no external AND'ing. */ 111 - ret = regmap_update_bits(regmap, ADP5585_PWM_CFG, 97 + ret = regmap_update_bits(regmap, info->pwm_cfg, 112 98 ADP5585_PWM_IN_AND | ADP5585_PWM_MODE | 113 99 ADP5585_PWM_EN, ADP5585_PWM_EN); 114 100 if (ret) 115 101 return ret; 116 102 117 - return regmap_set_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN); 103 + return regmap_set_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN); 118 104 } 119 105 120 106 static int pwm_adp5585_get_state(struct pwm_chip *chip, 121 107 struct pwm_device *pwm, 122 108 struct pwm_state *state) 123 109 { 124 - struct regmap *regmap = pwmchip_get_drvdata(chip); 110 + struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip); 111 + const struct adp5585_pwm_chip *info = adp5585_pwm->info; 112 + struct regmap *regmap = adp5585_pwm->regmap; 125 113 unsigned int on, off; 126 114 unsigned int val; 127 115 __le16 on_off; 128 116 int ret; 129 117 130 - ret = regmap_bulk_read(regmap, ADP5585_PWM_OFFT_LOW, &on_off, 2); 118 + ret = regmap_bulk_read(regmap, info->pwm_offt_low, &on_off, 2); 131 119 if (ret) 132 120 return ret; 133 121 off = le16_to_cpu(on_off); 134 122 135 - ret = regmap_bulk_read(regmap, ADP5585_PWM_ONT_LOW, &on_off, 2); 123 + ret = regmap_bulk_read(regmap, info->pwm_ont_low, &on_off, 2); 136 124 if (ret) 137 125 return ret; 138 126 on = le16_to_cpu(on_off); ··· 144 128 145 129 state->polarity = PWM_POLARITY_NORMAL; 146 130 147 - regmap_read(regmap, ADP5585_PWM_CFG, &val); 131 + regmap_read(regmap, info->pwm_cfg, &val); 148 132 state->enabled = !!(val & ADP5585_PWM_EN); 149 133 150 134 return 0; ··· 159 143 160 144 static int adp5585_pwm_probe(struct platform_device *pdev) 161 145 { 146 + const struct platform_device_id *id = platform_get_device_id(pdev); 162 147 struct device *dev = &pdev->dev; 163 148 struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent); 149 + struct adp5585_pwm *adp5585_pwm; 164 150 struct pwm_chip *chip; 165 151 int ret; 166 152 167 - chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM, 0); 153 + chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM, 154 + sizeof(*adp5585_pwm)); 168 155 if (IS_ERR(chip)) 169 156 return PTR_ERR(chip); 170 157 158 + adp5585_pwm = pwmchip_get_drvdata(chip); 159 + adp5585_pwm->regmap = adp5585->regmap; 160 + adp5585_pwm->ext_cfg = adp5585->regs->ext_cfg; 161 + 162 + adp5585_pwm->info = (const struct adp5585_pwm_chip *)id->driver_data; 163 + if (!adp5585_pwm->info) 164 + return -ENODEV; 165 + 171 166 device_set_of_node_from_dev(dev, dev->parent); 172 167 173 - pwmchip_set_drvdata(chip, adp5585->regmap); 174 168 chip->ops = &adp5585_pwm_ops; 175 169 176 170 ret = devm_pwmchip_add(dev, chip); ··· 190 164 return 0; 191 165 } 192 166 167 + static const struct adp5585_pwm_chip adp5589_pwm_chip_info = { 168 + .pwm_cfg = ADP5585_PWM_CFG, 169 + .pwm_offt_low = ADP5585_PWM_OFFT_LOW, 170 + .pwm_ont_low = ADP5585_PWM_ONT_LOW, 171 + }; 172 + 173 + static const struct adp5585_pwm_chip adp5585_pwm_chip_info = { 174 + .pwm_cfg = ADP5589_PWM_CFG, 175 + .pwm_offt_low = ADP5589_PWM_OFFT_LOW, 176 + .pwm_ont_low = ADP5589_PWM_ONT_LOW, 177 + }; 178 + 193 179 static const struct platform_device_id adp5585_pwm_id_table[] = { 194 - { "adp5585-pwm" }, 180 + { "adp5585-pwm", (kernel_ulong_t)&adp5585_pwm_chip_info }, 181 + { "adp5589-pwm", (kernel_ulong_t)&adp5589_pwm_chip_info }, 195 182 { /* Sentinel */ } 196 183 }; 197 184 MODULE_DEVICE_TABLE(platform, adp5585_pwm_id_table);
+3
include/linux/mfd/adp5585.h
··· 118 118 #define ADP5589_GPO_DATA_OUT_A 0x2a 119 119 #define ADP5589_GPO_OUT_MODE_A 0x2d 120 120 #define ADP5589_GPIO_DIRECTION_A 0x30 121 + #define ADP5589_PWM_OFFT_LOW 0x3e 122 + #define ADP5589_PWM_ONT_LOW 0x40 123 + #define ADP5589_PWM_CFG 0x42 121 124 #define ADP5589_PIN_CONFIG_D 0x4C 122 125 #define ADP5589_INT_EN 0x4e 123 126 #define ADP5589_MAX_REG ADP5589_INT_EN