1 /*
2 * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ite_it8xxx2_pwm
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/pwm.h>
11 #include <zephyr/drivers/pinctrl.h>
12 #include <zephyr/dt-bindings/pwm/it8xxx2_pwm.h>
13 #include <errno.h>
14 #include <zephyr/kernel.h>
15 #include <soc.h>
16 #include <soc_dt.h>
17 #include <stdlib.h>
18
19 #include <zephyr/logging/log.h>
20
21 LOG_MODULE_REGISTER(pwm_ite_it8xxx2, CONFIG_PWM_LOG_LEVEL);
22
23 #define PWM_CTRX_MIN 100
24 #define PWM_FREQ EC_FREQ
25 #define PCSSG_MASK 0x3
26
27 struct pwm_it8xxx2_cfg {
28 /* PWM channel duty cycle register */
29 uintptr_t reg_dcr;
30 /* PWM channel clock source selection register */
31 uintptr_t reg_pcssg;
32 /* PWM channel clock source gating register */
33 uintptr_t reg_pcsgr;
34 /* PWM channel output polarity register */
35 uintptr_t reg_pwmpol;
36 /* PWM channel */
37 int channel;
38 /* PWM prescaler control register base */
39 struct pwm_it8xxx2_regs *base;
40 /* Select PWM prescaler that output to PWM channel */
41 int prs_sel;
42 /* PWM alternate configuration */
43 const struct pinctrl_dev_config *pcfg;
44 };
45
46 struct pwm_it8xxx2_data {
47 uint32_t ctr;
48 uint32_t cxcprs;
49 uint32_t target_freq_prev;
50 };
51
pwm_enable(const struct device * dev,int enabled)52 static void pwm_enable(const struct device *dev, int enabled)
53 {
54 const struct pwm_it8xxx2_cfg *config = dev->config;
55 volatile uint8_t *reg_pcsgr = (uint8_t *)config->reg_pcsgr;
56 int ch = config->channel;
57
58 if (enabled) {
59 /* PWM channel clock source not gating */
60 *reg_pcsgr &= ~BIT(ch);
61 } else {
62 /* PWM channel clock source gating */
63 *reg_pcsgr |= BIT(ch);
64 }
65 }
66
pwm_it8xxx2_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)67 static int pwm_it8xxx2_get_cycles_per_sec(const struct device *dev,
68 uint32_t channel, uint64_t *cycles)
69 {
70 ARG_UNUSED(channel);
71
72 /*
73 * There are three ways to call pwm_it8xxx2_set_cycles() from pwm api:
74 * 1) pwm_set_cycles_usec() -> pwm_set_cycles_cycles() -> pwm_it8xxx2_set_cycles()
75 * target_freq = pwm_clk_src / period_cycles
76 * = cycles / (period * cycles / USEC_PER_SEC)
77 * = USEC_PER_SEC / period
78 * 2) pwm_set_cycles_nsec() -> pwm_set_cycles_cycles() -> pwm_it8xxx2_set_cycles()
79 * target_freq = pwm_clk_src / period_cycles
80 * = cycles / (period * cycles / NSEC_PER_SEC)
81 * = NSEC_PER_SEC / period
82 * 3) pwm_set_cycles_cycles() -> pwm_it8xxx2_set_cycles()
83 * target_freq = pwm_clk_src / period_cycles
84 * = cycles / period
85 *
86 * If we need to pwm output in EC power saving mode, then we will switch
87 * the prescaler clock source (cycles) from 8MHz to 32.768kHz. In order
88 * to get the same target_freq in the 3) case, we always return PWM_FREQ.
89 */
90 *cycles = (uint64_t) PWM_FREQ;
91
92 return 0;
93 }
94
pwm_it8xxx2_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)95 static int pwm_it8xxx2_set_cycles(const struct device *dev,
96 uint32_t channel, uint32_t period_cycles,
97 uint32_t pulse_cycles, pwm_flags_t flags)
98 {
99 const struct pwm_it8xxx2_cfg *config = dev->config;
100 struct pwm_it8xxx2_regs *const inst = config->base;
101 struct pwm_it8xxx2_data *data = dev->data;
102 volatile uint8_t *reg_dcr = (uint8_t *)config->reg_dcr;
103 volatile uint8_t *reg_pwmpol = (uint8_t *)config->reg_pwmpol;
104 int ch = config->channel;
105 int prs_sel = config->prs_sel;
106 uint32_t actual_freq = 0xffffffff, target_freq, deviation;
107 uint64_t pwm_clk_src;
108
109 /* Select PWM inverted polarity (ex. active-low pulse) */
110 if (flags & PWM_POLARITY_INVERTED) {
111 *reg_pwmpol |= BIT(ch);
112 } else {
113 *reg_pwmpol &= ~BIT(ch);
114 }
115
116 /* Enable PWM output open-drain */
117 if (flags & PWM_IT8XXX2_OPEN_DRAIN) {
118 inst->PWMODENR |= BIT(ch);
119 }
120
121 /* If pulse cycles is 0, set duty cycle 0 and enable pwm channel */
122 if (pulse_cycles == 0) {
123 *reg_dcr = 0;
124 pwm_enable(dev, 1);
125 return 0;
126 }
127
128 pwm_it8xxx2_get_cycles_per_sec(dev, channel, &pwm_clk_src);
129 target_freq = ((uint32_t) pwm_clk_src) / period_cycles;
130
131 /*
132 * Support PWM output frequency:
133 * 1) 8MHz clock source: 1Hz <= target_freq <= 79207Hz
134 * 2) 32.768KHz clock source: 1Hz <= target_freq <= 324Hz
135 * NOTE: PWM output signal maximum supported frequency comes from
136 * [8MHz or 32.768KHz] / 1 / (PWM_CTRX_MIN + 1).
137 * PWM output signal minimum supported frequency comes from
138 * [8MHz or 32.768KHz] / 65536 / 256, the minimum integer is 1.
139 */
140 if (target_freq < 1) {
141 LOG_ERR("PWM output frequency is < 1 !");
142 return -EINVAL;
143 }
144
145 deviation = (target_freq / 100) + 1;
146
147 /*
148 * Default clock source setting is 8MHz, when ITE chip is in power
149 * saving mode, clock source 8MHz will be gated (32.768KHz won't).
150 * So if we still need pwm output in mode, then we should set frequency
151 * <=324Hz in board dts. Now change prescaler clock source from 8MHz to
152 * 32.768KHz to support pwm output in mode.
153 */
154 if (target_freq <= 324) {
155 if (inst->PCFSR & BIT(prs_sel)) {
156 inst->PCFSR &= ~BIT(prs_sel);
157 }
158
159 pwm_clk_src = (uint64_t) 32768;
160 }
161
162 /*
163 * PWM output signal frequency is
164 * pwm_clk_src / ((CxCPRS[15:0] + 1) * (CTRx[7:0] + 1))
165 * NOTE: 1) define CTR minimum is 100 for more precisely when
166 * calculate DCR
167 * 2) CxCPRS[15:0] value 0001h results in a divisor 2
168 * CxCPRS[15:0] value FFFFh results in a divisor 65536
169 * CTRx[7:0] value 00h results in a divisor 1
170 * CTRx[7:0] value FFh results in a divisor 256
171 */
172 if (target_freq != data->target_freq_prev) {
173 uint32_t ctr, cxcprs;
174
175 for (ctr = 0xFF; ctr >= PWM_CTRX_MIN; ctr--) {
176 cxcprs = (((uint32_t) pwm_clk_src) / (ctr + 1) / target_freq);
177 /*
178 * Make sure cxcprs isn't zero, or we will have
179 * divide-by-zero on calculating actual_freq.
180 */
181 if (cxcprs != 0) {
182 actual_freq = ((uint32_t) pwm_clk_src) / (ctr + 1) / cxcprs;
183 if (abs(actual_freq - target_freq) < deviation) {
184 /* CxCPRS[15:0] = cxcprs - 1 */
185 cxcprs--;
186 break;
187 }
188 }
189 }
190
191 if (cxcprs > UINT16_MAX) {
192 LOG_ERR("PWM prescaler CxCPRS only support 2 bytes !");
193 return -EINVAL;
194 }
195
196 /* Store ctr and cxcprs with successful frequency change */
197 data->ctr = ctr;
198 data->cxcprs = cxcprs;
199 }
200
201 /* Set PWM prescaler clock divide and cycle time register */
202 if (prs_sel == PWM_PRESCALER_C4) {
203 inst->C4CPRS = data->cxcprs & 0xFF;
204 inst->C4MCPRS = (data->cxcprs >> 8) & 0xFF;
205 inst->CTR1 = data->ctr;
206 } else if (prs_sel == PWM_PRESCALER_C6) {
207 inst->C6CPRS = data->cxcprs & 0xFF;
208 inst->C6MCPRS = (data->cxcprs >> 8) & 0xFF;
209 inst->CTR2 = data->ctr;
210 } else if (prs_sel == PWM_PRESCALER_C7) {
211 inst->C7CPRS = data->cxcprs & 0xFF;
212 inst->C7MCPRS = (data->cxcprs >> 8) & 0xFF;
213 inst->CTR3 = data->ctr;
214 }
215
216 /* Set PWM channel duty cycle register */
217 *reg_dcr = (data->ctr * pulse_cycles) / period_cycles;
218
219 /* PWM channel clock source not gating */
220 pwm_enable(dev, 1);
221
222 /* Store the frequency to be compared */
223 data->target_freq_prev = target_freq;
224
225 LOG_DBG("clock source freq %d, target freq %d",
226 (uint32_t) pwm_clk_src, target_freq);
227
228 return 0;
229 }
230
pwm_it8xxx2_init(const struct device * dev)231 static int pwm_it8xxx2_init(const struct device *dev)
232 {
233 const struct pwm_it8xxx2_cfg *config = dev->config;
234 struct pwm_it8xxx2_regs *const inst = config->base;
235 volatile uint8_t *reg_pcssg = (uint8_t *)config->reg_pcssg;
236 int ch = config->channel;
237 int prs_sel = config->prs_sel;
238 int pcssg_shift;
239 int pcssg_mask;
240 int status;
241
242 /* PWM channel clock source gating before configuring */
243 pwm_enable(dev, 0);
244
245 /* Select clock source 8MHz for prescaler */
246 inst->PCFSR |= BIT(prs_sel);
247
248 /* Bit shift and mask of prescaler clock source select group register */
249 pcssg_shift = (ch % 4) * 2;
250 pcssg_mask = (prs_sel & PCSSG_MASK) << pcssg_shift;
251
252 /* Select which prescaler output to PWM channel */
253 *reg_pcssg &= ~(PCSSG_MASK << pcssg_shift);
254 *reg_pcssg |= pcssg_mask;
255
256 /*
257 * The cycle timer1 of it8320 later series was enhanced from
258 * 8bits to 10bits resolution, and others are still 8bit resolution.
259 * Because the cycle timer1 high byte default value is not zero,
260 * we clear cycle timer1 high byte at init and use it as 8-bit
261 * resolution like others.
262 */
263 inst->CTR1M = 0;
264
265 /* Enable PWMs clock counter */
266 inst->ZTIER |= IT8XXX2_PWM_PCCE;
267
268 /* Set alternate mode of PWM pin */
269 status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
270 if (status < 0) {
271 LOG_ERR("Failed to configure PWM pins");
272 return status;
273 }
274
275 return 0;
276 }
277
278 static DEVICE_API(pwm, pwm_it8xxx2_api) = {
279 .set_cycles = pwm_it8xxx2_set_cycles,
280 .get_cycles_per_sec = pwm_it8xxx2_get_cycles_per_sec,
281 };
282
283 /* Device Instance */
284 #define PWM_IT8XXX2_INIT(inst) \
285 PINCTRL_DT_INST_DEFINE(inst); \
286 \
287 static const struct pwm_it8xxx2_cfg pwm_it8xxx2_cfg_##inst = { \
288 .reg_dcr = DT_INST_REG_ADDR_BY_IDX(inst, 0), \
289 .reg_pcssg = DT_INST_REG_ADDR_BY_IDX(inst, 1), \
290 .reg_pcsgr = DT_INST_REG_ADDR_BY_IDX(inst, 2), \
291 .reg_pwmpol = DT_INST_REG_ADDR_BY_IDX(inst, 3), \
292 .channel = DT_PROP(DT_INST(inst, ite_it8xxx2_pwm), channel), \
293 .base = (struct pwm_it8xxx2_regs *) DT_REG_ADDR(DT_NODELABEL(prs)), \
294 .prs_sel = DT_PROP(DT_INST(inst, ite_it8xxx2_pwm), prescaler_cx), \
295 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
296 }; \
297 \
298 static struct pwm_it8xxx2_data pwm_it8xxx2_data_##inst; \
299 \
300 DEVICE_DT_INST_DEFINE(inst, \
301 &pwm_it8xxx2_init, \
302 NULL, \
303 &pwm_it8xxx2_data_##inst, \
304 &pwm_it8xxx2_cfg_##inst, \
305 PRE_KERNEL_1, \
306 CONFIG_PWM_INIT_PRIORITY, \
307 &pwm_it8xxx2_api);
308
309 DT_INST_FOREACH_STATUS_OKAY(PWM_IT8XXX2_INIT)
310