xref: /linux/drivers/pwm/pwm-mc33xs2410.c (revision 22c55fb9eb92395d999b8404d73e58540d11bdd8)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
4  *
5  * Reference Manual : https://www.nxp.com/docs/en/data-sheet/MC33XS2410.pdf
6  *
7  * Limitations:
8  * - Supports frequencies between 0.5Hz and 2048Hz with following steps:
9  *   - 0.5 Hz steps from 0.5 Hz to 32 Hz
10  *   - 2 Hz steps from 2 Hz to 128 Hz
11  *   - 8 Hz steps from 8 Hz to 512 Hz
12  *   - 32 Hz steps from 32 Hz to 2048 Hz
13  * - Cannot generate a 0 % duty cycle.
14  * - Always produces low output if disabled.
15  * - Configuration isn't atomic. When changing polarity, duty cycle or period
16  *   the data is taken immediately, counters not being affected, resulting in a
17  *   behavior of the output pin that is neither the old nor the new state,
18  *   rather something in between.
19  */
20 #define DEFAULT_SYMBOL_NAMESPACE		"PWM_MC33XS2410"
21 
22 #include <linux/auxiliary_bus.h>
23 #include <linux/bitfield.h>
24 #include <linux/delay.h>
25 #include <linux/err.h>
26 #include <linux/math64.h>
27 #include <linux/mc33xs2410.h>
28 #include <linux/minmax.h>
29 #include <linux/module.h>
30 #include <linux/of.h>
31 #include <linux/pwm.h>
32 
33 #include <linux/spi/spi.h>
34 
35 #define MC33XS2410_GLB_CTRL			0x00
36 #define MC33XS2410_GLB_CTRL_MODE		GENMASK(7, 6)
37 #define MC33XS2410_GLB_CTRL_MODE_NORMAL		FIELD_PREP(MC33XS2410_GLB_CTRL_MODE, 1)
38 
39 #define MC33XS2410_PWM_CTRL1			0x05
40 /* chan in { 1 ... 4 } */
41 #define MC33XS2410_PWM_CTRL1_POL_INV(chan)	BIT((chan) + 1)
42 
43 #define MC33XS2410_PWM_CTRL3			0x07
44 /* chan in { 1 ... 4 } */
45 #define MC33XS2410_PWM_CTRL3_EN(chan)		BIT(4 + (chan) - 1)
46 
47 /* chan in { 1 ... 4 } */
48 #define MC33XS2410_PWM_FREQ(chan)		(0x08 + (chan) - 1)
49 #define MC33XS2410_PWM_FREQ_STEP		GENMASK(7, 6)
50 #define MC33XS2410_PWM_FREQ_COUNT		GENMASK(5, 0)
51 
52 /* chan in { 1 ... 4 } */
53 #define MC33XS2410_PWM_DC(chan)			(0x0c + (chan) - 1)
54 
55 #define MC33XS2410_WDT				0x14
56 
57 #define MC33XS2410_PWM_MIN_PERIOD		488282
58 /* step in { 0 ... 3 } */
59 #define MC33XS2410_PWM_MAX_PERIOD(step)		(2000000000 >> (2 * (step)))
60 
61 #define MC33XS2410_FRAME_IN_ADDR		GENMASK(15, 8)
62 #define MC33XS2410_FRAME_IN_DATA		GENMASK(7, 0)
63 #define MC33XS2410_FRAME_IN_ADDR_WR		BIT(7)
64 #define MC33XS2410_FRAME_IN_DATA_RD		BIT(7)
65 #define MC33XS2410_FRAME_OUT_DATA		GENMASK(13, 0)
66 
67 #define MC33XS2410_MAX_TRANSFERS		5
68 
69 static int mc33xs2410_write_regs(struct spi_device *spi, u8 *reg, u8 *val,
70 				 unsigned int len)
71 {
72 	u16 tx[MC33XS2410_MAX_TRANSFERS];
73 	int i;
74 
75 	if (len > MC33XS2410_MAX_TRANSFERS)
76 		return -EINVAL;
77 
78 	for (i = 0; i < len; i++)
79 		tx[i] = FIELD_PREP(MC33XS2410_FRAME_IN_DATA, val[i]) |
80 			FIELD_PREP(MC33XS2410_FRAME_IN_ADDR,
81 				   MC33XS2410_FRAME_IN_ADDR_WR | reg[i]);
82 
83 	return spi_write(spi, tx, len * 2);
84 }
85 
86 static int mc33xs2410_read_regs(struct spi_device *spi, u8 *reg, u8 flag,
87 				u16 *val, unsigned int len)
88 {
89 	u16 tx[MC33XS2410_MAX_TRANSFERS];
90 	u16 rx[MC33XS2410_MAX_TRANSFERS];
91 	struct spi_transfer t = {
92 		.tx_buf = tx,
93 		.rx_buf = rx,
94 	};
95 	int i, ret;
96 
97 	len++;
98 	if (len > MC33XS2410_MAX_TRANSFERS)
99 		return -EINVAL;
100 
101 	t.len = len * 2;
102 	for (i = 0; i < len - 1; i++)
103 		tx[i] = FIELD_PREP(MC33XS2410_FRAME_IN_DATA, flag) |
104 			FIELD_PREP(MC33XS2410_FRAME_IN_ADDR, reg[i]);
105 
106 	ret = spi_sync_transfer(spi, &t, 1);
107 	if (ret < 0)
108 		return ret;
109 
110 	for (i = 1; i < len; i++)
111 		val[i - 1] = FIELD_GET(MC33XS2410_FRAME_OUT_DATA, rx[i]);
112 
113 	return 0;
114 }
115 
116 static int mc33xs2410_write_reg(struct spi_device *spi, u8 reg, u8 val)
117 {
118 	return mc33xs2410_write_regs(spi, &reg, &val, 1);
119 }
120 
121 static int mc33xs2410_read_reg(struct spi_device *spi, u8 reg, u16 *val, u8 flag)
122 {
123 	return mc33xs2410_read_regs(spi, &reg, flag, val, 1);
124 }
125 
126 int mc33xs2410_read_reg_ctrl(struct spi_device *spi, u8 reg, u16 *val)
127 {
128 	return mc33xs2410_read_reg(spi, reg, val, MC33XS2410_FRAME_IN_DATA_RD);
129 }
130 EXPORT_SYMBOL_GPL(mc33xs2410_read_reg_ctrl);
131 
132 int mc33xs2410_read_reg_diag(struct spi_device *spi, u8 reg, u16 *val)
133 {
134 	return mc33xs2410_read_reg(spi, reg, val, 0);
135 }
136 EXPORT_SYMBOL_GPL(mc33xs2410_read_reg_diag);
137 
138 int mc33xs2410_modify_reg(struct spi_device *spi, u8 reg, u8 mask, u8 val)
139 {
140 	u16 tmp;
141 	int ret;
142 
143 	ret = mc33xs2410_read_reg_ctrl(spi, reg, &tmp);
144 	if (ret < 0)
145 		return ret;
146 
147 	tmp &= ~mask;
148 	tmp |= val & mask;
149 
150 	return mc33xs2410_write_reg(spi, reg, tmp);
151 }
152 EXPORT_SYMBOL_GPL(mc33xs2410_modify_reg);
153 
154 static u8 mc33xs2410_pwm_get_freq(u64 period)
155 {
156 	u8 step, count;
157 
158 	/*
159 	 * Check which step [0 .. 3] is appropriate for the given period. The
160 	 * period ranges for the different step values overlap. Prefer big step
161 	 * values as these allow more finegrained period and duty cycle
162 	 * selection.
163 	 */
164 
165 	switch (period) {
166 	case MC33XS2410_PWM_MIN_PERIOD ... MC33XS2410_PWM_MAX_PERIOD(3):
167 		step = 3;
168 		break;
169 	case MC33XS2410_PWM_MAX_PERIOD(3) + 1 ... MC33XS2410_PWM_MAX_PERIOD(2):
170 		step = 2;
171 		break;
172 	case MC33XS2410_PWM_MAX_PERIOD(2) + 1 ... MC33XS2410_PWM_MAX_PERIOD(1):
173 		step = 1;
174 		break;
175 	case MC33XS2410_PWM_MAX_PERIOD(1) + 1 ... MC33XS2410_PWM_MAX_PERIOD(0):
176 		step = 0;
177 		break;
178 	}
179 
180 	/*
181 	 * Round up here because a higher count results in a higher frequency
182 	 * and so a smaller period.
183 	 */
184 	count = DIV_ROUND_UP((u32)MC33XS2410_PWM_MAX_PERIOD(step), (u32)period);
185 	return FIELD_PREP(MC33XS2410_PWM_FREQ_STEP, step) |
186 	       FIELD_PREP(MC33XS2410_PWM_FREQ_COUNT, count - 1);
187 }
188 
189 static u64 mc33xs2410_pwm_get_period(u8 reg)
190 {
191 	u32 doubled_freq, code, doubled_steps;
192 
193 	/*
194 	 * steps:
195 	 *   - 0 = 0.5Hz
196 	 *   - 1 = 2Hz
197 	 *   - 2 = 8Hz
198 	 *   - 3 = 32Hz
199 	 * frequency = (code + 1) x steps.
200 	 *
201 	 * To avoid losing precision in case steps value is zero, scale the
202 	 * steps value for now by two and keep it in mind when calculating the
203 	 * period that the frequency had been doubled.
204 	 */
205 	doubled_steps = 1 << (FIELD_GET(MC33XS2410_PWM_FREQ_STEP, reg) * 2);
206 	code = FIELD_GET(MC33XS2410_PWM_FREQ_COUNT, reg);
207 	doubled_freq = (code + 1) * doubled_steps;
208 
209 	/* Convert frequency to period, considering the doubled frequency. */
210 	return DIV_ROUND_UP(2 * NSEC_PER_SEC, doubled_freq);
211 }
212 
213 /*
214  * The hardware cannot generate a 0% relative duty cycle for normal and inversed
215  * polarity. For normal polarity, the channel must be disabled, the device then
216  * emits a constant low signal.
217  * For inverted polarity, the channel must be enabled, the polarity must be set
218  * to normal and the relative duty cylce must be set to 100%. The device then
219  * emits a constant high signal.
220  */
221 static int mc33xs2410_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
222 				const struct pwm_state *state)
223 {
224 	struct spi_device *spi = pwmchip_get_drvdata(chip);
225 	u8 reg[4] = {
226 			MC33XS2410_PWM_FREQ(pwm->hwpwm + 1),
227 			MC33XS2410_PWM_DC(pwm->hwpwm + 1),
228 			MC33XS2410_PWM_CTRL1,
229 			MC33XS2410_PWM_CTRL3
230 		    };
231 	u64 period, duty_cycle;
232 	int ret, rel_dc;
233 	u16 rd_val[2];
234 	u8 wr_val[4];
235 	u8 mask;
236 
237 	period = min(state->period, MC33XS2410_PWM_MAX_PERIOD(0));
238 	if (period < MC33XS2410_PWM_MIN_PERIOD)
239 		return -EINVAL;
240 
241 	ret = mc33xs2410_read_regs(spi, &reg[2], MC33XS2410_FRAME_IN_DATA_RD, rd_val, 2);
242 	if (ret < 0)
243 		return ret;
244 
245 	/* Frequency */
246 	wr_val[0] = mc33xs2410_pwm_get_freq(period);
247 	/* Continue calculations with the possibly truncated period */
248 	period = mc33xs2410_pwm_get_period(wr_val[0]);
249 
250 	/* Duty cycle */
251 	duty_cycle = min(period, state->duty_cycle);
252 	rel_dc = div64_u64(duty_cycle * 256, period) - 1;
253 	if (rel_dc >= 0)
254 		wr_val[1] = rel_dc;
255 	else if (state->polarity == PWM_POLARITY_NORMAL)
256 		wr_val[1] = 0;
257 	else
258 		wr_val[1] = 255;
259 
260 	/* Polarity */
261 	mask = MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm + 1);
262 	if (state->polarity == PWM_POLARITY_INVERSED && rel_dc >= 0)
263 		wr_val[2] = rd_val[0] | mask;
264 	else
265 		wr_val[2] = rd_val[0] & ~mask;
266 
267 	/* Enable */
268 	mask = MC33XS2410_PWM_CTRL3_EN(pwm->hwpwm + 1);
269 	if (state->enabled &&
270 	    !(state->polarity == PWM_POLARITY_NORMAL && rel_dc < 0))
271 		wr_val[3] = rd_val[1] | mask;
272 	else
273 		wr_val[3] = rd_val[1] & ~mask;
274 
275 	return mc33xs2410_write_regs(spi, reg, wr_val, 4);
276 }
277 
278 static int mc33xs2410_pwm_get_state(struct pwm_chip *chip,
279 				    struct pwm_device *pwm,
280 				    struct pwm_state *state)
281 {
282 	struct spi_device *spi = pwmchip_get_drvdata(chip);
283 	u8 reg[4] = {
284 			MC33XS2410_PWM_FREQ(pwm->hwpwm + 1),
285 			MC33XS2410_PWM_DC(pwm->hwpwm + 1),
286 			MC33XS2410_PWM_CTRL1,
287 			MC33XS2410_PWM_CTRL3,
288 		    };
289 	u16 val[4];
290 	int ret;
291 
292 	ret = mc33xs2410_read_regs(spi, reg, MC33XS2410_FRAME_IN_DATA_RD, val,
293 				   ARRAY_SIZE(reg));
294 	if (ret < 0)
295 		return ret;
296 
297 	state->period = mc33xs2410_pwm_get_period(val[0]);
298 	state->polarity = (val[2] & MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm + 1)) ?
299 			  PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
300 	state->enabled = !!(val[3] & MC33XS2410_PWM_CTRL3_EN(pwm->hwpwm + 1));
301 	state->duty_cycle = DIV_ROUND_UP_ULL((val[1] + 1) * state->period, 256);
302 
303 	return 0;
304 }
305 
306 static const struct pwm_ops mc33xs2410_pwm_ops = {
307 	.apply = mc33xs2410_pwm_apply,
308 	.get_state = mc33xs2410_pwm_get_state,
309 };
310 
311 static int mc33xs2410_reset(struct device *dev)
312 {
313 	struct gpio_desc *reset_gpio;
314 
315 	reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
316 	if (IS_ERR_OR_NULL(reset_gpio))
317 		return PTR_ERR_OR_ZERO(reset_gpio);
318 
319 	/* Wake-up time */
320 	fsleep(10000);
321 
322 	return 0;
323 }
324 
325 static int mc33xs2410_probe(struct spi_device *spi)
326 {
327 	struct device *dev = &spi->dev;
328 	struct auxiliary_device *adev;
329 	struct pwm_chip *chip;
330 	int ret;
331 
332 	chip = devm_pwmchip_alloc(dev, 4, 0);
333 	if (IS_ERR(chip))
334 		return PTR_ERR(chip);
335 
336 	spi->bits_per_word = 16;
337 	spi->mode |= SPI_CS_WORD;
338 	ret = spi_setup(spi);
339 	if (ret < 0)
340 		return ret;
341 
342 	pwmchip_set_drvdata(chip, spi);
343 	chip->ops = &mc33xs2410_pwm_ops;
344 
345 	/*
346 	 * Deasserts the reset of the device. Shouldn't change the output signal
347 	 * if the device was setup prior to probing.
348 	 */
349 	ret = mc33xs2410_reset(dev);
350 	if (ret)
351 		return ret;
352 
353 	/*
354 	 * Disable watchdog and keep in mind that the watchdog won't trigger a
355 	 * reset of the machine when running into an timeout, instead the
356 	 * control over the outputs is handed over to the INx input logic
357 	 * signals of the device. Disabling it here just deactivates this
358 	 * feature until a proper solution is found.
359 	 */
360 	ret = mc33xs2410_write_reg(spi, MC33XS2410_WDT, 0x0);
361 	if (ret < 0)
362 		return dev_err_probe(dev, ret, "Failed to disable watchdog\n");
363 
364 	/* Transition to normal mode */
365 	ret = mc33xs2410_modify_reg(spi, MC33XS2410_GLB_CTRL,
366 				    MC33XS2410_GLB_CTRL_MODE,
367 				    MC33XS2410_GLB_CTRL_MODE_NORMAL);
368 	if (ret < 0)
369 		return dev_err_probe(dev, ret,
370 				     "Failed to transition to normal mode\n");
371 
372 	ret = devm_pwmchip_add(dev, chip);
373 	if (ret < 0)
374 		return dev_err_probe(dev, ret, "Failed to add pwm chip\n");
375 
376 	adev = devm_auxiliary_device_create(dev, "hwmon", NULL);
377 	if (!adev)
378 		return dev_err_probe(dev, -ENODEV, "Failed to register hwmon device\n");
379 
380 	return 0;
381 }
382 
383 static const struct spi_device_id mc33xs2410_spi_id[] = {
384 	{ "mc33xs2410" },
385 	{ }
386 };
387 MODULE_DEVICE_TABLE(spi, mc33xs2410_spi_id);
388 
389 static const struct of_device_id mc33xs2410_of_match[] = {
390 	{ .compatible = "nxp,mc33xs2410" },
391 	{ }
392 };
393 MODULE_DEVICE_TABLE(of, mc33xs2410_of_match);
394 
395 static struct spi_driver mc33xs2410_driver = {
396 	.driver = {
397 		.name = "mc33xs2410-pwm",
398 		.of_match_table = mc33xs2410_of_match,
399 	},
400 	.probe = mc33xs2410_probe,
401 	.id_table = mc33xs2410_spi_id,
402 };
403 module_spi_driver(mc33xs2410_driver);
404 
405 MODULE_DESCRIPTION("NXP MC33XS2410 high-side switch driver");
406 MODULE_AUTHOR("Dimitri Fedrau <dimitri.fedrau@liebherr.com>");
407 MODULE_LICENSE("GPL");
408