Lines Matching +full:axi +full:- +full:pwmgen +full:- +full:2

1 // SPDX-License-Identifier: GPL-2.0
3 * Analog Devices AXI PWM generator
11 * - The writes to registers for period and duty are shadowed until
14 * - Writing LOAD_CONFIG also has the effect of re-synchronizing all
18 * - Supports normal polarity. Does not support changing polarity.
19 * - On disable, the PWM output becomes low (inactive).
24 #include <linux/fpga/adi-axi-common.h>
79 if (wf->period_length_ns == 0) { in axi_pwmgen_round_waveform_tohw()
86 /* With ddata->clk_rate_hz < NSEC_PER_SEC this won't overflow. */ in axi_pwmgen_round_waveform_tohw()
87 wfhw->period_cnt = min_t(u64, in axi_pwmgen_round_waveform_tohw()
88 mul_u64_u32_div(wf->period_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC), in axi_pwmgen_round_waveform_tohw()
91 if (wfhw->period_cnt == 0) { in axi_pwmgen_round_waveform_tohw()
97 wfhw->period_cnt = 1; in axi_pwmgen_round_waveform_tohw()
98 wfhw->duty_cycle_cnt = 0; in axi_pwmgen_round_waveform_tohw()
99 wfhw->duty_offset_cnt = 0; in axi_pwmgen_round_waveform_tohw()
101 wfhw->duty_cycle_cnt = min_t(u64, in axi_pwmgen_round_waveform_tohw()
102 mul_u64_u32_div(wf->duty_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC), in axi_pwmgen_round_waveform_tohw()
104 wfhw->duty_offset_cnt = min_t(u64, in axi_pwmgen_round_waveform_tohw()
105 mul_u64_u32_div(wf->duty_offset_ns, ddata->clk_rate_hz, NSEC_PER_SEC), in axi_pwmgen_round_waveform_tohw()
110 dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> PERIOD: %08x, DUTY: %08x, OFFSET: %08x\n", in axi_pwmgen_round_waveform_tohw()
111 pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, in axi_pwmgen_round_waveform_tohw()
112 ddata->clk_rate_hz, wfhw->period_cnt, wfhw->duty_cycle_cnt, wfhw->duty_offset_cnt); in axi_pwmgen_round_waveform_tohw()
123 wf->period_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->period_cnt * NSEC_PER_SEC, in axi_pwmgen_round_waveform_fromhw()
124 ddata->clk_rate_hz); in axi_pwmgen_round_waveform_fromhw()
126 wf->duty_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_cycle_cnt * NSEC_PER_SEC, in axi_pwmgen_round_waveform_fromhw()
127 ddata->clk_rate_hz); in axi_pwmgen_round_waveform_fromhw()
129 wf->duty_offset_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_offset_cnt * NSEC_PER_SEC, in axi_pwmgen_round_waveform_fromhw()
130 ddata->clk_rate_hz); in axi_pwmgen_round_waveform_fromhw()
141 struct regmap *regmap = ddata->regmap; in axi_pwmgen_write_waveform()
142 unsigned int ch = pwm->hwpwm; in axi_pwmgen_write_waveform()
145 ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), wfhw->period_cnt); in axi_pwmgen_write_waveform()
149 ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), wfhw->duty_cycle_cnt); in axi_pwmgen_write_waveform()
153 ret = regmap_write(regmap, AXI_PWMGEN_CHX_OFFSET(ch), wfhw->duty_offset_cnt); in axi_pwmgen_write_waveform()
166 struct regmap *regmap = ddata->regmap; in axi_pwmgen_read_waveform()
167 unsigned int ch = pwm->hwpwm; in axi_pwmgen_read_waveform()
170 ret = regmap_read(regmap, AXI_PWMGEN_CHX_PERIOD(ch), &wfhw->period_cnt); in axi_pwmgen_read_waveform()
174 ret = regmap_read(regmap, AXI_PWMGEN_CHX_DUTY(ch), &wfhw->duty_cycle_cnt); in axi_pwmgen_read_waveform()
178 ret = regmap_read(regmap, AXI_PWMGEN_CHX_OFFSET(ch), &wfhw->duty_offset_cnt); in axi_pwmgen_read_waveform()
182 if (wfhw->duty_cycle_cnt > wfhw->period_cnt) in axi_pwmgen_read_waveform()
183 wfhw->duty_cycle_cnt = wfhw->period_cnt; in axi_pwmgen_read_waveform()
186 if (wfhw->duty_offset_cnt >= wfhw->period_cnt) { in axi_pwmgen_read_waveform()
187 wfhw->duty_cycle_cnt = 0; in axi_pwmgen_read_waveform()
188 wfhw->duty_offset_cnt = 0; in axi_pwmgen_read_waveform()
212 return dev_err_probe(dev, -ENODEV, in axi_pwmgen_setup()
220 if (ADI_AXI_PCORE_VER_MAJOR(val) != 2) { in axi_pwmgen_setup()
221 return dev_err_probe(dev, -ENODEV, "Unsupported peripheral version %u.%u.%u\n", in axi_pwmgen_setup()
252 struct device *dev = &pdev->dev; in axi_pwmgen_probe()
277 ddata->regmap = regmap; in axi_pwmgen_probe()
287 ddata->clk_rate_hz = clk_get_rate(clk); in axi_pwmgen_probe()
288 if (!ddata->clk_rate_hz || ddata->clk_rate_hz > NSEC_PER_SEC) in axi_pwmgen_probe()
289 return dev_err_probe(dev, -EINVAL, in axi_pwmgen_probe()
290 "Invalid clock rate: %lu\n", ddata->clk_rate_hz); in axi_pwmgen_probe()
292 chip->ops = &axi_pwmgen_pwm_ops; in axi_pwmgen_probe()
293 chip->atomic = true; in axi_pwmgen_probe()
303 { .compatible = "adi,axi-pwmgen-2.00.a" },
310 .name = "axi-pwmgen",
320 MODULE_DESCRIPTION("Driver for the Analog Devices AXI PWM generator");