1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Analog Devices AXI PWM generator 4 * 5 * Copyright 2024 Analog Devices Inc. 6 * Copyright 2024 Baylibre SAS 7 * 8 * Device docs: https://analogdevicesinc.github.io/hdl/library/axi_pwm_gen/index.html 9 * 10 * Limitations: 11 * - The writes to registers for period and duty are shadowed until 12 * LOAD_CONFIG is written to AXI_PWMGEN_REG_CONFIG, at which point 13 * they take effect. 14 * - Writing LOAD_CONFIG also has the effect of re-synchronizing all 15 * enabled channels, which could cause glitching on other channels. It 16 * is therefore expected that channels are assigned harmonic periods 17 * and all have a single user coordinating this. 18 * - Supports normal polarity. Does not support changing polarity. 19 * - On disable, the PWM output becomes low (inactive). 20 */ 21 #include <linux/bits.h> 22 #include <linux/clk.h> 23 #include <linux/err.h> 24 #include <linux/fpga/adi-axi-common.h> 25 #include <linux/io.h> 26 #include <linux/minmax.h> 27 #include <linux/module.h> 28 #include <linux/platform_device.h> 29 #include <linux/pwm.h> 30 #include <linux/regmap.h> 31 #include <linux/slab.h> 32 33 #define AXI_PWMGEN_REG_ID 0x04 34 #define AXI_PWMGEN_REG_SCRATCHPAD 0x08 35 #define AXI_PWMGEN_REG_CORE_MAGIC 0x0C 36 #define AXI_PWMGEN_REG_CONFIG 0x10 37 #define AXI_PWMGEN_REG_NPWM 0x14 38 #define AXI_PWMGEN_CHX_PERIOD(ch) (0x40 + (4 * (ch))) 39 #define AXI_PWMGEN_CHX_DUTY(ch) (0x80 + (4 * (ch))) 40 #define AXI_PWMGEN_CHX_OFFSET(ch) (0xC0 + (4 * (ch))) 41 #define AXI_PWMGEN_REG_CORE_MAGIC_VAL 0x601A3471 /* Identification number to test during setup */ 42 #define AXI_PWMGEN_LOAD_CONFIG BIT(1) 43 #define AXI_PWMGEN_REG_CONFIG_RESET BIT(0) 44 45 struct axi_pwmgen_ddata { 46 struct regmap *regmap; 47 unsigned long clk_rate_hz; 48 }; 49 50 static const struct regmap_config axi_pwmgen_regmap_config = { 51 .reg_bits = 32, 52 .reg_stride = 4, 53 .val_bits = 32, 54 .max_register = 0xFC, 55 }; 56 57 /* This represents a hardware configuration for one channel */ 58 struct axi_pwmgen_waveform { 59 u32 period_cnt; 60 u32 duty_cycle_cnt; 61 u32 duty_offset_cnt; 62 }; 63 64 static int axi_pwmgen_round_waveform_tohw(struct pwm_chip *chip, 65 struct pwm_device *pwm, 66 const struct pwm_waveform *wf, 67 void *_wfhw) 68 { 69 struct axi_pwmgen_waveform *wfhw = _wfhw; 70 struct axi_pwmgen_ddata *ddata = pwmchip_get_drvdata(chip); 71 72 if (wf->period_length_ns == 0) { 73 *wfhw = (struct axi_pwmgen_waveform){ 74 .period_cnt = 0, 75 .duty_cycle_cnt = 0, 76 .duty_offset_cnt = 0, 77 }; 78 } else { 79 /* With ddata->clk_rate_hz < NSEC_PER_SEC this won't overflow. */ 80 wfhw->period_cnt = min_t(u64, 81 mul_u64_u32_div(wf->period_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC), 82 U32_MAX); 83 84 if (wfhw->period_cnt == 0) { 85 /* 86 * The specified period is too short for the hardware. 87 * Let's round .duty_cycle down to 0 to get a (somewhat) 88 * valid result. 89 */ 90 wfhw->period_cnt = 1; 91 wfhw->duty_cycle_cnt = 0; 92 wfhw->duty_offset_cnt = 0; 93 } else { 94 wfhw->duty_cycle_cnt = min_t(u64, 95 mul_u64_u32_div(wf->duty_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC), 96 U32_MAX); 97 wfhw->duty_offset_cnt = min_t(u64, 98 mul_u64_u32_div(wf->duty_offset_ns, ddata->clk_rate_hz, NSEC_PER_SEC), 99 U32_MAX); 100 } 101 } 102 103 dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> PERIOD: %08x, DUTY: %08x, OFFSET: %08x\n", 104 pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, 105 ddata->clk_rate_hz, wfhw->period_cnt, wfhw->duty_cycle_cnt, wfhw->duty_offset_cnt); 106 107 return 0; 108 } 109 110 static int axi_pwmgen_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm, 111 const void *_wfhw, struct pwm_waveform *wf) 112 { 113 const struct axi_pwmgen_waveform *wfhw = _wfhw; 114 struct axi_pwmgen_ddata *ddata = pwmchip_get_drvdata(chip); 115 116 wf->period_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->period_cnt * NSEC_PER_SEC, 117 ddata->clk_rate_hz); 118 119 wf->duty_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_cycle_cnt * NSEC_PER_SEC, 120 ddata->clk_rate_hz); 121 122 wf->duty_offset_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_offset_cnt * NSEC_PER_SEC, 123 ddata->clk_rate_hz); 124 125 return 0; 126 } 127 128 static int axi_pwmgen_write_waveform(struct pwm_chip *chip, 129 struct pwm_device *pwm, 130 const void *_wfhw) 131 { 132 const struct axi_pwmgen_waveform *wfhw = _wfhw; 133 struct axi_pwmgen_ddata *ddata = pwmchip_get_drvdata(chip); 134 struct regmap *regmap = ddata->regmap; 135 unsigned int ch = pwm->hwpwm; 136 int ret; 137 138 ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), wfhw->period_cnt); 139 if (ret) 140 return ret; 141 142 ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), wfhw->duty_cycle_cnt); 143 if (ret) 144 return ret; 145 146 ret = regmap_write(regmap, AXI_PWMGEN_CHX_OFFSET(ch), wfhw->duty_offset_cnt); 147 if (ret) 148 return ret; 149 150 return regmap_write(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONFIG); 151 } 152 153 static int axi_pwmgen_read_waveform(struct pwm_chip *chip, 154 struct pwm_device *pwm, 155 void *_wfhw) 156 { 157 struct axi_pwmgen_waveform *wfhw = _wfhw; 158 struct axi_pwmgen_ddata *ddata = pwmchip_get_drvdata(chip); 159 struct regmap *regmap = ddata->regmap; 160 unsigned int ch = pwm->hwpwm; 161 int ret; 162 163 ret = regmap_read(regmap, AXI_PWMGEN_CHX_PERIOD(ch), &wfhw->period_cnt); 164 if (ret) 165 return ret; 166 167 ret = regmap_read(regmap, AXI_PWMGEN_CHX_DUTY(ch), &wfhw->duty_cycle_cnt); 168 if (ret) 169 return ret; 170 171 ret = regmap_read(regmap, AXI_PWMGEN_CHX_OFFSET(ch), &wfhw->duty_offset_cnt); 172 if (ret) 173 return ret; 174 175 if (wfhw->duty_cycle_cnt > wfhw->period_cnt) 176 wfhw->duty_cycle_cnt = wfhw->period_cnt; 177 178 /* XXX: is this the actual behaviour of the hardware? */ 179 if (wfhw->duty_offset_cnt >= wfhw->period_cnt) { 180 wfhw->duty_cycle_cnt = 0; 181 wfhw->duty_offset_cnt = 0; 182 } 183 184 return 0; 185 } 186 187 static const struct pwm_ops axi_pwmgen_pwm_ops = { 188 .sizeof_wfhw = sizeof(struct axi_pwmgen_waveform), 189 .round_waveform_tohw = axi_pwmgen_round_waveform_tohw, 190 .round_waveform_fromhw = axi_pwmgen_round_waveform_fromhw, 191 .read_waveform = axi_pwmgen_read_waveform, 192 .write_waveform = axi_pwmgen_write_waveform, 193 }; 194 195 static int axi_pwmgen_setup(struct regmap *regmap, struct device *dev) 196 { 197 int ret; 198 u32 val; 199 200 ret = regmap_read(regmap, AXI_PWMGEN_REG_CORE_MAGIC, &val); 201 if (ret) 202 return ret; 203 204 if (val != AXI_PWMGEN_REG_CORE_MAGIC_VAL) 205 return dev_err_probe(dev, -ENODEV, 206 "failed to read expected value from register: got %08x, expected %08x\n", 207 val, AXI_PWMGEN_REG_CORE_MAGIC_VAL); 208 209 ret = regmap_read(regmap, ADI_AXI_REG_VERSION, &val); 210 if (ret) 211 return ret; 212 213 if (ADI_AXI_PCORE_VER_MAJOR(val) != 2) { 214 return dev_err_probe(dev, -ENODEV, "Unsupported peripheral version %u.%u.%u\n", 215 ADI_AXI_PCORE_VER_MAJOR(val), 216 ADI_AXI_PCORE_VER_MINOR(val), 217 ADI_AXI_PCORE_VER_PATCH(val)); 218 } 219 220 /* Enable the core */ 221 ret = regmap_clear_bits(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_REG_CONFIG_RESET); 222 if (ret) 223 return ret; 224 225 ret = regmap_read(regmap, AXI_PWMGEN_REG_NPWM, &val); 226 if (ret) 227 return ret; 228 229 /* Return the number of PWMs */ 230 return val; 231 } 232 233 static int axi_pwmgen_probe(struct platform_device *pdev) 234 { 235 struct device *dev = &pdev->dev; 236 struct regmap *regmap; 237 struct pwm_chip *chip; 238 struct axi_pwmgen_ddata *ddata; 239 struct clk *clk; 240 void __iomem *io_base; 241 int ret; 242 243 io_base = devm_platform_ioremap_resource(pdev, 0); 244 if (IS_ERR(io_base)) 245 return PTR_ERR(io_base); 246 247 regmap = devm_regmap_init_mmio(dev, io_base, &axi_pwmgen_regmap_config); 248 if (IS_ERR(regmap)) 249 return dev_err_probe(dev, PTR_ERR(regmap), 250 "failed to init register map\n"); 251 252 ret = axi_pwmgen_setup(regmap, dev); 253 if (ret < 0) 254 return ret; 255 256 chip = devm_pwmchip_alloc(dev, ret, sizeof(*ddata)); 257 if (IS_ERR(chip)) 258 return PTR_ERR(chip); 259 ddata = pwmchip_get_drvdata(chip); 260 ddata->regmap = regmap; 261 262 clk = devm_clk_get_enabled(dev, NULL); 263 if (IS_ERR(clk)) 264 return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); 265 266 ret = devm_clk_rate_exclusive_get(dev, clk); 267 if (ret) 268 return dev_err_probe(dev, ret, "failed to get exclusive rate\n"); 269 270 ddata->clk_rate_hz = clk_get_rate(clk); 271 if (!ddata->clk_rate_hz || ddata->clk_rate_hz > NSEC_PER_SEC) 272 return dev_err_probe(dev, -EINVAL, 273 "Invalid clock rate: %lu\n", ddata->clk_rate_hz); 274 275 chip->ops = &axi_pwmgen_pwm_ops; 276 chip->atomic = true; 277 278 ret = devm_pwmchip_add(dev, chip); 279 if (ret) 280 return dev_err_probe(dev, ret, "could not add PWM chip\n"); 281 282 return 0; 283 } 284 285 static const struct of_device_id axi_pwmgen_ids[] = { 286 { .compatible = "adi,axi-pwmgen-2.00.a" }, 287 { } 288 }; 289 MODULE_DEVICE_TABLE(of, axi_pwmgen_ids); 290 291 static struct platform_driver axi_pwmgen_driver = { 292 .driver = { 293 .name = "axi-pwmgen", 294 .of_match_table = axi_pwmgen_ids, 295 }, 296 .probe = axi_pwmgen_probe, 297 }; 298 module_platform_driver(axi_pwmgen_driver); 299 300 MODULE_LICENSE("GPL"); 301 MODULE_AUTHOR("Sergiu Cuciurean <sergiu.cuciurean@analog.com>"); 302 MODULE_AUTHOR("Trevor Gamblin <tgamblin@baylibre.com>"); 303 MODULE_DESCRIPTION("Driver for the Analog Devices AXI PWM generator"); 304