1 /*
2  * Copyright (c) 2021 Teslabs Engineering S.L.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT gd_gd32_pwm
8 
9 #include <errno.h>
10 
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/drivers/clock_control/gd32.h>
13 #include <zephyr/drivers/pwm.h>
14 #include <zephyr/drivers/pinctrl.h>
15 #include <zephyr/drivers/reset.h>
16 #include <zephyr/sys/util_macro.h>
17 
18 #include <gd32_timer.h>
19 
20 #include <zephyr/logging/log.h>
21 
22 LOG_MODULE_REGISTER(pwm_gd32, CONFIG_PWM_LOG_LEVEL);
23 
24 /** PWM data. */
25 struct pwm_gd32_data {
26 	/** Timer clock (Hz). */
27 	uint32_t tim_clk;
28 };
29 
30 /** PWM configuration. */
31 struct pwm_gd32_config {
32 	/** Timer register. */
33 	uint32_t reg;
34 	/** Number of channels */
35 	uint8_t channels;
36 	/** Flag to indicate if timer has 32-bit counter */
37 	bool is_32bit;
38 	/** Flag to indicate if timer is advanced */
39 	bool is_advanced;
40 	/** Prescaler. */
41 	uint16_t prescaler;
42 	/** Clock id. */
43 	uint16_t clkid;
44 	/** Reset. */
45 	struct reset_dt_spec reset;
46 	/** pinctrl configurations. */
47 	const struct pinctrl_dev_config *pcfg;
48 };
49 
50 /** Obtain channel enable bit for the given channel */
51 #define TIMER_CHCTL2_CHXEN(ch) BIT(4U * (ch))
52 /** Obtain polarity bit for the given channel */
53 #define TIMER_CHCTL2_CHXP(ch) BIT(1U + (4U * (ch)))
54 /** Obtain CHCTL0/1 mask for the given channel (0 or 1) */
55 #define TIMER_CHCTLX_MSK(ch) (0xFU << (8U * (ch)))
56 
57 /** Obtain RCU register offset from RCU clock value */
58 #define RCU_CLOCK_OFFSET(rcu_clock) ((rcu_clock) >> 6U)
59 
pwm_gd32_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)60 static int pwm_gd32_set_cycles(const struct device *dev, uint32_t channel,
61 			      uint32_t period_cycles, uint32_t pulse_cycles,
62 			      pwm_flags_t flags)
63 {
64 	const struct pwm_gd32_config *config = dev->config;
65 
66 	if (channel >= config->channels) {
67 		return -EINVAL;
68 	}
69 
70 	/* 16-bit timers can count up to UINT16_MAX */
71 	if (!config->is_32bit && (period_cycles > UINT16_MAX)) {
72 		return -ENOTSUP;
73 	}
74 
75 	/* disable channel output if period is zero */
76 	if (period_cycles == 0U) {
77 		TIMER_CHCTL2(config->reg) &= ~TIMER_CHCTL2_CHXEN(channel);
78 		return 0;
79 	}
80 
81 	/* update polarity */
82 	if ((flags & PWM_POLARITY_INVERTED) != 0U) {
83 		TIMER_CHCTL2(config->reg) |= TIMER_CHCTL2_CHXP(channel);
84 	} else {
85 		TIMER_CHCTL2(config->reg) &= ~TIMER_CHCTL2_CHXP(channel);
86 	}
87 
88 	/* update pulse */
89 	switch (channel) {
90 	case 0U:
91 		TIMER_CH0CV(config->reg) = pulse_cycles;
92 		break;
93 	case 1U:
94 		TIMER_CH1CV(config->reg) = pulse_cycles;
95 		break;
96 	case 2U:
97 		TIMER_CH2CV(config->reg) = pulse_cycles;
98 		break;
99 	case 3U:
100 		TIMER_CH3CV(config->reg) = pulse_cycles;
101 		break;
102 	default:
103 		__ASSERT_NO_MSG(NULL);
104 		break;
105 	}
106 
107 	/* update period */
108 	TIMER_CAR(config->reg) = period_cycles;
109 
110 	/* channel not enabled: configure it */
111 	if ((TIMER_CHCTL2(config->reg) & TIMER_CHCTL2_CHXEN(channel)) == 0U) {
112 		volatile uint32_t *chctl;
113 
114 		/* select PWM1 mode, enable OC shadowing */
115 		if (channel < 2U) {
116 			chctl = &TIMER_CHCTL0(config->reg);
117 		} else {
118 			chctl = &TIMER_CHCTL1(config->reg);
119 		}
120 
121 		*chctl &= ~TIMER_CHCTLX_MSK(channel);
122 		*chctl |= (TIMER_OC_MODE_PWM1 | TIMER_OC_SHADOW_ENABLE) <<
123 			  (8U * (channel % 2U));
124 
125 		/* enable channel output */
126 		TIMER_CHCTL2(config->reg) |= TIMER_CHCTL2_CHXEN(channel);
127 
128 		/* generate update event (to load shadow values) */
129 		TIMER_SWEVG(config->reg) |= TIMER_SWEVG_UPG;
130 	}
131 
132 	return 0;
133 }
134 
pwm_gd32_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)135 static int pwm_gd32_get_cycles_per_sec(const struct device *dev,
136 				       uint32_t channel, uint64_t *cycles)
137 {
138 	struct pwm_gd32_data *data = dev->data;
139 	const struct pwm_gd32_config *config = dev->config;
140 
141 	*cycles = (uint64_t)(data->tim_clk / (config->prescaler + 1U));
142 
143 	return 0;
144 }
145 
146 static const struct pwm_driver_api pwm_gd32_driver_api = {
147 	.set_cycles = pwm_gd32_set_cycles,
148 	.get_cycles_per_sec = pwm_gd32_get_cycles_per_sec,
149 };
150 
pwm_gd32_init(const struct device * dev)151 static int pwm_gd32_init(const struct device *dev)
152 {
153 	const struct pwm_gd32_config *config = dev->config;
154 	struct pwm_gd32_data *data = dev->data;
155 	int ret;
156 
157 	(void)clock_control_on(GD32_CLOCK_CONTROLLER,
158 			       (clock_control_subsys_t)&config->clkid);
159 
160 	(void)reset_line_toggle_dt(&config->reset);
161 
162 	/* apply pin configuration */
163 	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
164 	if (ret < 0) {
165 		return ret;
166 	}
167 
168 	/* cache timer clock value */
169 	(void)clock_control_get_rate(GD32_CLOCK_CONTROLLER,
170 				     (clock_control_subsys_t)&config->clkid,
171 				     &data->tim_clk);
172 
173 	/* basic timer operation: edge aligned, up counting, shadowed CAR */
174 	TIMER_CTL0(config->reg) = TIMER_CKDIV_DIV1 | TIMER_COUNTER_EDGE |
175 				  TIMER_COUNTER_UP | TIMER_CTL0_ARSE;
176 	TIMER_PSC(config->reg) = config->prescaler;
177 
178 	/* enable primary output for advanced timers */
179 	if (config->is_advanced) {
180 		TIMER_CCHP(config->reg) |= TIMER_CCHP_POEN;
181 	}
182 
183 	/* enable timer counter */
184 	TIMER_CTL0(config->reg) |= TIMER_CTL0_CEN;
185 
186 	return 0;
187 }
188 
189 #define PWM_GD32_DEFINE(i)						       \
190 	static struct pwm_gd32_data pwm_gd32_data_##i;			       \
191 									       \
192 	PINCTRL_DT_INST_DEFINE(i);					       \
193 									       \
194 	static const struct pwm_gd32_config pwm_gd32_config_##i = {	       \
195 		.reg = DT_REG_ADDR(DT_INST_PARENT(i)),			       \
196 		.clkid = DT_CLOCKS_CELL(DT_INST_PARENT(i), id),		       \
197 		.reset = RESET_DT_SPEC_GET(DT_INST_PARENT(i)),		       \
198 		.prescaler = DT_PROP(DT_INST_PARENT(i), prescaler),	       \
199 		.channels = DT_PROP(DT_INST_PARENT(i), channels),	       \
200 		.is_32bit = DT_PROP(DT_INST_PARENT(i), is_32bit),	       \
201 		.is_advanced = DT_PROP(DT_INST_PARENT(i), is_advanced),	       \
202 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i),		       \
203 	};								       \
204 									       \
205 	DEVICE_DT_INST_DEFINE(i, &pwm_gd32_init, NULL, &pwm_gd32_data_##i,     \
206 			      &pwm_gd32_config_##i, POST_KERNEL,	       \
207 			      CONFIG_PWM_INIT_PRIORITY,			       \
208 			      &pwm_gd32_driver_api);
209 
210 DT_INST_FOREACH_STATUS_OKAY(PWM_GD32_DEFINE)
211