xref: /linux/drivers/pwm/pwm-axi-pwmgen.c (revision fcb3ad4366b9c810cbb9da34c076a9a52d8aa1e0)
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_RSTN, 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_RSTN		0x10
37 #define   AXI_PWMGEN_REG_RSTN_LOAD_CONFIG	BIT(1)
38 #define   AXI_PWMGEN_REG_RSTN_RESET		BIT(0)
39 #define AXI_PWMGEN_REG_NPWM		0x14
40 #define AXI_PWMGEN_REG_CONFIG		0x18
41 #define   AXI_PWMGEN_REG_CONFIG_FORCE_ALIGN	BIT(1)
42 #define AXI_PWMGEN_CHX_PERIOD(ch)	(0x40 + (4 * (ch)))
43 #define AXI_PWMGEN_CHX_DUTY(ch)		(0x80 + (4 * (ch)))
44 #define AXI_PWMGEN_CHX_OFFSET(ch)	(0xC0 + (4 * (ch)))
45 #define AXI_PWMGEN_REG_CORE_MAGIC_VAL	0x601A3471 /* Identification number to test during setup */
46 
47 struct axi_pwmgen_ddata {
48 	struct regmap *regmap;
49 	unsigned long clk_rate_hz;
50 };
51 
52 static const struct regmap_config axi_pwmgen_regmap_config = {
53 	.reg_bits = 32,
54 	.reg_stride = 4,
55 	.val_bits = 32,
56 	.max_register = 0xFC,
57 };
58 
59 /* This represents a hardware configuration for one channel */
60 struct axi_pwmgen_waveform {
61 	u32 period_cnt;
62 	u32 duty_cycle_cnt;
63 	u32 duty_offset_cnt;
64 };
65 
66 static struct axi_pwmgen_ddata *axi_pwmgen_ddata_from_chip(struct pwm_chip *chip)
67 {
68 	return pwmchip_get_drvdata(chip);
69 }
70 
71 static int axi_pwmgen_round_waveform_tohw(struct pwm_chip *chip,
72 					  struct pwm_device *pwm,
73 					  const struct pwm_waveform *wf,
74 					  void *_wfhw)
75 {
76 	struct axi_pwmgen_waveform *wfhw = _wfhw;
77 	struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip);
78 
79 	if (wf->period_length_ns == 0) {
80 		*wfhw = (struct axi_pwmgen_waveform){
81 			.period_cnt = 0,
82 			.duty_cycle_cnt = 0,
83 			.duty_offset_cnt = 0,
84 		};
85 	} else {
86 		/* With ddata->clk_rate_hz < NSEC_PER_SEC this won't overflow. */
87 		wfhw->period_cnt = min_t(u64,
88 					 mul_u64_u32_div(wf->period_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC),
89 					 U32_MAX);
90 
91 		if (wfhw->period_cnt == 0) {
92 			/*
93 			 * The specified period is too short for the hardware.
94 			 * Let's round .duty_cycle down to 0 to get a (somewhat)
95 			 * valid result.
96 			 */
97 			wfhw->period_cnt = 1;
98 			wfhw->duty_cycle_cnt = 0;
99 			wfhw->duty_offset_cnt = 0;
100 		} else {
101 			wfhw->duty_cycle_cnt = min_t(u64,
102 						     mul_u64_u32_div(wf->duty_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC),
103 						     U32_MAX);
104 			wfhw->duty_offset_cnt = min_t(u64,
105 						      mul_u64_u32_div(wf->duty_offset_ns, ddata->clk_rate_hz, NSEC_PER_SEC),
106 						      U32_MAX);
107 		}
108 	}
109 
110 	dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> PERIOD: %08x, DUTY: %08x, OFFSET: %08x\n",
111 		pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns,
112 		ddata->clk_rate_hz, wfhw->period_cnt, wfhw->duty_cycle_cnt, wfhw->duty_offset_cnt);
113 
114 	return 0;
115 }
116 
117 static int axi_pwmgen_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm,
118 					     const void *_wfhw, struct pwm_waveform *wf)
119 {
120 	const struct axi_pwmgen_waveform *wfhw = _wfhw;
121 	struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip);
122 
123 	wf->period_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->period_cnt * NSEC_PER_SEC,
124 					ddata->clk_rate_hz);
125 
126 	wf->duty_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_cycle_cnt * NSEC_PER_SEC,
127 					    ddata->clk_rate_hz);
128 
129 	wf->duty_offset_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_offset_cnt * NSEC_PER_SEC,
130 					     ddata->clk_rate_hz);
131 
132 	return 0;
133 }
134 
135 static int axi_pwmgen_write_waveform(struct pwm_chip *chip,
136 				     struct pwm_device *pwm,
137 				     const void *_wfhw)
138 {
139 	const struct axi_pwmgen_waveform *wfhw = _wfhw;
140 	struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip);
141 	struct regmap *regmap = ddata->regmap;
142 	unsigned int ch = pwm->hwpwm;
143 	int ret;
144 
145 	ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), wfhw->period_cnt);
146 	if (ret)
147 		return ret;
148 
149 	ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), wfhw->duty_cycle_cnt);
150 	if (ret)
151 		return ret;
152 
153 	ret = regmap_write(regmap, AXI_PWMGEN_CHX_OFFSET(ch), wfhw->duty_offset_cnt);
154 	if (ret)
155 		return ret;
156 
157 	return regmap_write(regmap, AXI_PWMGEN_REG_RSTN, AXI_PWMGEN_REG_RSTN_LOAD_CONFIG);
158 }
159 
160 static int axi_pwmgen_read_waveform(struct pwm_chip *chip,
161 				    struct pwm_device *pwm,
162 				    void *_wfhw)
163 {
164 	struct axi_pwmgen_waveform *wfhw = _wfhw;
165 	struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip);
166 	struct regmap *regmap = ddata->regmap;
167 	unsigned int ch = pwm->hwpwm;
168 	int ret;
169 
170 	ret = regmap_read(regmap, AXI_PWMGEN_CHX_PERIOD(ch), &wfhw->period_cnt);
171 	if (ret)
172 		return ret;
173 
174 	ret = regmap_read(regmap, AXI_PWMGEN_CHX_DUTY(ch), &wfhw->duty_cycle_cnt);
175 	if (ret)
176 		return ret;
177 
178 	ret = regmap_read(regmap, AXI_PWMGEN_CHX_OFFSET(ch), &wfhw->duty_offset_cnt);
179 	if (ret)
180 		return ret;
181 
182 	if (wfhw->duty_cycle_cnt > wfhw->period_cnt)
183 		wfhw->duty_cycle_cnt = wfhw->period_cnt;
184 
185 	/* XXX: is this the actual behaviour of the hardware? */
186 	if (wfhw->duty_offset_cnt >= wfhw->period_cnt) {
187 		wfhw->duty_cycle_cnt = 0;
188 		wfhw->duty_offset_cnt = 0;
189 	}
190 
191 	return 0;
192 }
193 
194 static const struct pwm_ops axi_pwmgen_pwm_ops = {
195 	.sizeof_wfhw = sizeof(struct axi_pwmgen_waveform),
196 	.round_waveform_tohw = axi_pwmgen_round_waveform_tohw,
197 	.round_waveform_fromhw = axi_pwmgen_round_waveform_fromhw,
198 	.read_waveform = axi_pwmgen_read_waveform,
199 	.write_waveform = axi_pwmgen_write_waveform,
200 };
201 
202 static int axi_pwmgen_setup(struct regmap *regmap, struct device *dev)
203 {
204 	int ret;
205 	u32 val;
206 
207 	ret = regmap_read(regmap, AXI_PWMGEN_REG_CORE_MAGIC, &val);
208 	if (ret)
209 		return ret;
210 
211 	if (val != AXI_PWMGEN_REG_CORE_MAGIC_VAL)
212 		return dev_err_probe(dev, -ENODEV,
213 			"failed to read expected value from register: got %08x, expected %08x\n",
214 			val, AXI_PWMGEN_REG_CORE_MAGIC_VAL);
215 
216 	ret = regmap_read(regmap, ADI_AXI_REG_VERSION, &val);
217 	if (ret)
218 		return ret;
219 
220 	if (ADI_AXI_PCORE_VER_MAJOR(val) != 2) {
221 		return dev_err_probe(dev, -ENODEV, "Unsupported peripheral version %u.%u.%u\n",
222 			ADI_AXI_PCORE_VER_MAJOR(val),
223 			ADI_AXI_PCORE_VER_MINOR(val),
224 			ADI_AXI_PCORE_VER_PATCH(val));
225 	}
226 
227 	/* Enable the core */
228 	ret = regmap_clear_bits(regmap, AXI_PWMGEN_REG_RSTN, AXI_PWMGEN_REG_RSTN_RESET);
229 	if (ret)
230 		return ret;
231 
232 	/*
233 	 * Enable force align so that changes to PWM period and duty cycle take
234 	 * effect immediately. Otherwise, the effect of the change is delayed
235 	 * until the period of all channels run out, which can be long after the
236 	 * apply function returns.
237 	 */
238 	ret = regmap_set_bits(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_REG_CONFIG_FORCE_ALIGN);
239 	if (ret)
240 		return ret;
241 
242 	ret = regmap_read(regmap, AXI_PWMGEN_REG_NPWM, &val);
243 	if (ret)
244 		return ret;
245 
246 	/* Return the number of PWMs */
247 	return val;
248 }
249 
250 static int axi_pwmgen_probe(struct platform_device *pdev)
251 {
252 	struct device *dev = &pdev->dev;
253 	struct regmap *regmap;
254 	struct pwm_chip *chip;
255 	struct axi_pwmgen_ddata *ddata;
256 	struct clk *clk;
257 	void __iomem *io_base;
258 	int ret;
259 
260 	io_base = devm_platform_ioremap_resource(pdev, 0);
261 	if (IS_ERR(io_base))
262 		return PTR_ERR(io_base);
263 
264 	regmap = devm_regmap_init_mmio(dev, io_base, &axi_pwmgen_regmap_config);
265 	if (IS_ERR(regmap))
266 		return dev_err_probe(dev, PTR_ERR(regmap),
267 				     "failed to init register map\n");
268 
269 	ret = axi_pwmgen_setup(regmap, dev);
270 	if (ret < 0)
271 		return ret;
272 
273 	chip = devm_pwmchip_alloc(dev, ret, sizeof(*ddata));
274 	if (IS_ERR(chip))
275 		return PTR_ERR(chip);
276 	ddata = pwmchip_get_drvdata(chip);
277 	ddata->regmap = regmap;
278 
279 	clk = devm_clk_get_enabled(dev, NULL);
280 	if (IS_ERR(clk))
281 		return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
282 
283 	ret = devm_clk_rate_exclusive_get(dev, clk);
284 	if (ret)
285 		return dev_err_probe(dev, ret, "failed to get exclusive rate\n");
286 
287 	ddata->clk_rate_hz = clk_get_rate(clk);
288 	if (!ddata->clk_rate_hz || ddata->clk_rate_hz > NSEC_PER_SEC)
289 		return dev_err_probe(dev, -EINVAL,
290 				     "Invalid clock rate: %lu\n", ddata->clk_rate_hz);
291 
292 	chip->ops = &axi_pwmgen_pwm_ops;
293 	chip->atomic = true;
294 
295 	ret = devm_pwmchip_add(dev, chip);
296 	if (ret)
297 		return dev_err_probe(dev, ret, "could not add PWM chip\n");
298 
299 	return 0;
300 }
301 
302 static const struct of_device_id axi_pwmgen_ids[] = {
303 	{ .compatible = "adi,axi-pwmgen-2.00.a" },
304 	{ }
305 };
306 MODULE_DEVICE_TABLE(of, axi_pwmgen_ids);
307 
308 static struct platform_driver axi_pwmgen_driver = {
309 	.driver = {
310 		.name = "axi-pwmgen",
311 		.of_match_table = axi_pwmgen_ids,
312 	},
313 	.probe = axi_pwmgen_probe,
314 };
315 module_platform_driver(axi_pwmgen_driver);
316 
317 MODULE_LICENSE("GPL");
318 MODULE_AUTHOR("Sergiu Cuciurean <sergiu.cuciurean@analog.com>");
319 MODULE_AUTHOR("Trevor Gamblin <tgamblin@baylibre.com>");
320 MODULE_DESCRIPTION("Driver for the Analog Devices AXI PWM generator");
321