1 /*
2  * Copyright (c) 2023 SLB
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT infineon_xmc4xxx_ccu4_pwm
8 
9 #include <soc.h>
10 #include <zephyr/dt-bindings/pwm/pwm.h>
11 #include <zephyr/drivers/pwm.h>
12 #include <zephyr/drivers/pinctrl.h>
13 
14 #include <xmc_ccu4.h>
15 #include <xmc_scu.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(pwm_xmc4xxx_ccu4, CONFIG_PWM_LOG_LEVEL);
19 
20 #define NUM_SLICES 4
21 #define NUM_CHANNELS NUM_SLICES
22 #define SLICE_ADDR_FROM_MODULE(module_ptr, idx) ((uint32_t)(module_ptr) + ((idx) + 1) * 0x100)
23 
24 struct pwm_xmc4xxx_ccu4_config {
25 	XMC_CCU4_MODULE_t *ccu4;
26 	const struct pinctrl_dev_config *pcfg;
27 	const uint8_t slice_prescaler[NUM_SLICES];
28 };
29 
pwm_xmc4xxx_ccu4_init(const struct device * dev)30 static int pwm_xmc4xxx_ccu4_init(const struct device *dev)
31 {
32 	const struct pwm_xmc4xxx_ccu4_config *config = dev->config;
33 
34 	/* enables the CCU4 clock and ungates clock to CCU4x */
35 	XMC_CCU4_EnableModule(config->ccu4);
36 	XMC_CCU4_StartPrescaler(config->ccu4);
37 
38 	for (int i = 0; i < NUM_SLICES; i++) {
39 		XMC_CCU4_SLICE_t *slice;
40 		XMC_CCU4_SLICE_COMPARE_CONFIG_t slice_conf = {
41 			.prescaler_initval = config->slice_prescaler[i]
42 		};
43 
44 		slice = (XMC_CCU4_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu4, i);
45 		XMC_CCU4_SLICE_CompareInit(slice, &slice_conf);
46 	}
47 
48 	return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
49 }
50 
pwm_xmc4xxx_ccu4_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)51 static int pwm_xmc4xxx_ccu4_set_cycles(const struct device *dev, uint32_t channel,
52 			      uint32_t period_cycles, uint32_t pulse_cycles,
53 			      pwm_flags_t flags)
54 {
55 	const struct pwm_xmc4xxx_ccu4_config *config = dev->config;
56 	XMC_CCU4_SLICE_t *slice;
57 	int slice_idx = channel;
58 
59 	if (channel >= NUM_CHANNELS) {
60 		return -EINVAL;
61 	}
62 
63 	if (period_cycles == 0 || period_cycles > UINT16_MAX + 1 || pulse_cycles > UINT16_MAX) {
64 		return -EINVAL;
65 	}
66 
67 	slice = (XMC_CCU4_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu4, slice_idx);
68 	slice->PRS = period_cycles - 1;
69 	slice->CRS = period_cycles - pulse_cycles;
70 	slice->PSL = flags & PWM_POLARITY_INVERTED;
71 
72 	XMC_CCU4_EnableShadowTransfer(config->ccu4, BIT(slice_idx * 4));
73 
74 	/* start if not already running */
75 	XMC_CCU4_EnableClock(config->ccu4, slice_idx);
76 	XMC_CCU4_SLICE_StartTimer(slice);
77 
78 	return 0;
79 }
80 
pwm_xmc4xxx_ccu4_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)81 static int pwm_xmc4xxx_ccu4_get_cycles_per_sec(const struct device *dev, uint32_t channel,
82 					       uint64_t *cycles)
83 {
84 	const struct pwm_xmc4xxx_ccu4_config *config = dev->config;
85 	int slice_idx = channel;
86 
87 	if (channel >= NUM_SLICES) {
88 		return -EINVAL;
89 	}
90 
91 	*cycles = XMC_SCU_CLOCK_GetCcuClockFrequency() >> config->slice_prescaler[slice_idx];
92 
93 	return 0;
94 }
95 
96 static const struct pwm_driver_api pwm_xmc4xxx_ccu4_driver_api = {
97 	.set_cycles = pwm_xmc4xxx_ccu4_set_cycles,
98 	.get_cycles_per_sec = pwm_xmc4xxx_ccu4_get_cycles_per_sec,
99 };
100 
101 #define PWM_XMC4XXX_CCU4_INIT(n)                                                           \
102 PINCTRL_DT_INST_DEFINE(n);                                                                 \
103 											   \
104 static const struct pwm_xmc4xxx_ccu4_config config##n = {                                  \
105 	.ccu4 = (CCU4_GLOBAL_TypeDef *)DT_INST_REG_ADDR(n),                                \
106 	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),                                         \
107 	.slice_prescaler = DT_INST_PROP(n, slice_prescaler)};                              \
108 											   \
109 DEVICE_DT_INST_DEFINE(n, pwm_xmc4xxx_ccu4_init, NULL, NULL, &config##n, POST_KERNEL,       \
110 		      CONFIG_PWM_INIT_PRIORITY, &pwm_xmc4xxx_ccu4_driver_api);
111 
112 DT_INST_FOREACH_STATUS_OKAY(PWM_XMC4XXX_CCU4_INIT)
113