1 /*
2  * Copyright (c) 2022 IoT.bzh
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT renesas_pwm_rcar
8 
9 #include <errno.h>
10 
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/drivers/clock_control/renesas_cpg_mssr.h>
14 #include <zephyr/drivers/pinctrl.h>
15 #include <zephyr/drivers/pwm.h>
16 
17 #include <soc.h>
18 
19 #define LOG_LEVEL CONFIG_PWM_LOG_LEVEL
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(pwm_rcar);
22 
23 /* PWM Controller capabilities */
24 #define RCAR_PWM_MAX_CYCLE   1023U
25 #define RCAR_PWM_MAX_DIV     24U
26 #define RCAR_PWM_MAX_CHANNEL 6
27 
28 /* Registers */
29 #define RCAR_PWM_REG_SHIFT 0x1000
30 #define RCAR_PWM_CR(channel)                                                                       \
31 	((uint32_t)((channel * RCAR_PWM_REG_SHIFT)) + 0x00) /* PWM Control Register */
32 #define RCAR_PWM_CNT(channel)                                                                      \
33 	((uint32_t)((channel * RCAR_PWM_REG_SHIFT)) + 0x04) /* PWM Count Register */
34 
35 /* PWMCR (PWM Control Register) */
36 #define RCAR_PWM_CR_CC_MASK  0x000f0000 /* Clock Control */
37 #define RCAR_PWM_CR_CC_SHIFT 16
38 #define RCAR_PWM_CR_CCMD     BIT(15) /* Frequency Division Mode */
39 #define RCAR_PWM_CR_SYNC     BIT(11)
40 #define RCAR_PWM_CR_SS	     BIT(4) /* Single Pulse Output */
41 #define RCAR_PWM_CR_EN	     BIT(0) /* Channel Enable */
42 
43 /* PWM Diviser is on 5 bits (CC combined with CCMD) */
44 #define RCAR_PWM_DIVISER_MASK  (RCAR_PWM_CR_CC_MASK | RCAR_PWM_CR_CCMD)
45 #define RCAR_PWM_DIVISER_SHIFT 15
46 
47 /* PWMCNT (PWM Count Register) */
48 #define RCAR_PWM_CNT_CYC_MASK  0x03ff0000 /* PWM Cycle */
49 #define RCAR_PWM_CNT_CYC_SHIFT 16
50 #define RCAR_PWM_CNT_PH_MASK   0x000003ff /* PWM High-Level Period */
51 #define RCAR_PWM_CNT_PH_SHIFT  0
52 
53 struct pwm_rcar_cfg {
54 	uint32_t reg_addr;
55 	const struct device *clock_dev;
56 	struct rcar_cpg_clk core_clk;
57 	struct rcar_cpg_clk mod_clk;
58 	const struct pinctrl_dev_config *pcfg;
59 };
60 
61 struct pwm_rcar_data {
62 	uint32_t clk_rate;
63 };
64 
pwm_rcar_read(const struct pwm_rcar_cfg * config,uint32_t offs)65 static uint32_t pwm_rcar_read(const struct pwm_rcar_cfg *config, uint32_t offs)
66 {
67 	return sys_read32(config->reg_addr + offs);
68 }
69 
pwm_rcar_write(const struct pwm_rcar_cfg * config,uint32_t offs,uint32_t value)70 static void pwm_rcar_write(const struct pwm_rcar_cfg *config, uint32_t offs, uint32_t value)
71 {
72 	sys_write32(value, config->reg_addr + offs);
73 }
74 
pwm_rcar_write_bit(const struct pwm_rcar_cfg * config,uint32_t offs,uint32_t bits,bool value)75 static void pwm_rcar_write_bit(const struct pwm_rcar_cfg *config, uint32_t offs, uint32_t bits,
76 			       bool value)
77 {
78 	uint32_t reg_val = pwm_rcar_read(config, offs);
79 
80 	if (value) {
81 		reg_val |= bits;
82 	} else {
83 		reg_val &= ~(bits);
84 	}
85 
86 	pwm_rcar_write(config, offs, reg_val);
87 }
88 
pwm_rcar_update_clk(const struct pwm_rcar_cfg * config,uint32_t channel,uint32_t * period_cycles,uint32_t * pulse_cycles)89 static int pwm_rcar_update_clk(const struct pwm_rcar_cfg *config, uint32_t channel,
90 			       uint32_t *period_cycles, uint32_t *pulse_cycles)
91 {
92 	uint32_t reg_val, power, diviser;
93 
94 	power = pwm_rcar_read(config, RCAR_PWM_CR(channel)) & RCAR_PWM_DIVISER_MASK;
95 	power = power >> RCAR_PWM_DIVISER_SHIFT;
96 	diviser = 1 << power;
97 
98 	LOG_DBG("Found old diviser : 2^%d=%d", power, diviser);
99 
100 	/* Looking for the best possible clock diviser */
101 	if (*period_cycles > RCAR_PWM_MAX_CYCLE) {
102 		/* Reducing clock speed */
103 		while (*period_cycles > RCAR_PWM_MAX_CYCLE) {
104 			diviser *= 2;
105 			*period_cycles /= 2;
106 			*pulse_cycles /= 2;
107 			power++;
108 			if (power > RCAR_PWM_MAX_DIV) {
109 				return -ENOTSUP;
110 			}
111 		}
112 	} else {
113 		/* Increasing clock speed */
114 		while (*period_cycles < (RCAR_PWM_MAX_CYCLE / 2)) {
115 			if (power == 0) {
116 				return -ENOTSUP;
117 			}
118 			diviser /= 2;
119 			*period_cycles *= 2;
120 			*pulse_cycles *= 2;
121 			power--;
122 		}
123 	}
124 	LOG_DBG("Found new diviser : 2^%d=%d\n", power, diviser);
125 
126 	/* Set new clock Diviser */
127 	reg_val = pwm_rcar_read(config, RCAR_PWM_CR(channel));
128 	reg_val &= ~RCAR_PWM_DIVISER_MASK;
129 	reg_val |= (power << RCAR_PWM_DIVISER_SHIFT);
130 	pwm_rcar_write(config, RCAR_PWM_CR(channel), reg_val);
131 
132 	return 0;
133 }
134 
pwm_rcar_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)135 static int pwm_rcar_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles,
136 			       uint32_t pulse_cycles, pwm_flags_t flags)
137 {
138 	const struct pwm_rcar_cfg *config = dev->config;
139 	uint32_t reg_val;
140 	int ret = 0;
141 
142 	if (channel > RCAR_PWM_MAX_CHANNEL) {
143 		return -ENOTSUP;
144 	}
145 
146 	if (flags != PWM_POLARITY_NORMAL) {
147 		return -ENOTSUP;
148 	}
149 
150 	/* Prohibited values */
151 	if (period_cycles == 0U || pulse_cycles == 0U || pulse_cycles > period_cycles) {
152 		return -EINVAL;
153 	}
154 
155 	LOG_DBG("base_reg=0x%x, pulse_cycles=%d, period_cycles=%d,"
156 		" duty_cycle=%d",
157 		config->reg_addr, pulse_cycles, period_cycles,
158 		(pulse_cycles * 100U / period_cycles));
159 
160 	/* Disable PWM */
161 	pwm_rcar_write_bit(config, RCAR_PWM_CR(channel), RCAR_PWM_CR_EN, false);
162 
163 	/* Set continuous mode */
164 	pwm_rcar_write_bit(config, RCAR_PWM_CR(channel), RCAR_PWM_CR_SS, false);
165 
166 	/* Enable SYNC mode */
167 	pwm_rcar_write_bit(config, RCAR_PWM_CR(channel), RCAR_PWM_CR_SYNC, true);
168 
169 	/*
170 	 * Set clock counter according to the requested period_cycles
171 	 * if period_cycles is less than half of the counter, then the
172 	 * clock diviser could be updated as the diviser is a modulo 2.
173 	 */
174 	if (period_cycles > RCAR_PWM_MAX_CYCLE || period_cycles < (RCAR_PWM_MAX_CYCLE / 2)) {
175 		LOG_DBG("Adapting frequency diviser...");
176 		ret = pwm_rcar_update_clk(config, channel, &period_cycles, &pulse_cycles);
177 		if (ret != 0) {
178 			return ret;
179 		}
180 	}
181 
182 	/* Set total period cycle */
183 	reg_val = pwm_rcar_read(config, RCAR_PWM_CNT(channel));
184 	reg_val &= ~(RCAR_PWM_CNT_CYC_MASK);
185 	reg_val |= (period_cycles << RCAR_PWM_CNT_CYC_SHIFT);
186 	pwm_rcar_write(config, RCAR_PWM_CNT(channel), reg_val);
187 
188 	/* Set high level period cycle */
189 	reg_val = pwm_rcar_read(config, RCAR_PWM_CNT(channel));
190 	reg_val &= ~(RCAR_PWM_CNT_PH_MASK);
191 	reg_val |= (pulse_cycles << RCAR_PWM_CNT_PH_SHIFT);
192 	pwm_rcar_write(config, RCAR_PWM_CNT(channel), reg_val);
193 
194 	/* Enable PWM */
195 	pwm_rcar_write_bit(config, RCAR_PWM_CR(channel), RCAR_PWM_CR_EN, true);
196 
197 	return ret;
198 }
199 
pwm_rcar_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)200 static int pwm_rcar_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles)
201 {
202 	const struct pwm_rcar_cfg *config = dev->config;
203 	struct pwm_rcar_data *data = dev->data;
204 	uint32_t diviser;
205 
206 	if (channel > RCAR_PWM_MAX_CHANNEL) {
207 		return -ENOTSUP;
208 	}
209 
210 	diviser = pwm_rcar_read(config, RCAR_PWM_CR(channel)) & RCAR_PWM_DIVISER_MASK;
211 	diviser = diviser >> RCAR_PWM_DIVISER_SHIFT;
212 	*cycles = data->clk_rate >> diviser;
213 
214 	LOG_DBG("Actual division: %d and Frequency: %d Hz", diviser, (uint32_t)*cycles);
215 
216 	return 0;
217 }
218 
pwm_rcar_init(const struct device * dev)219 static int pwm_rcar_init(const struct device *dev)
220 {
221 	const struct pwm_rcar_cfg *config = dev->config;
222 	struct pwm_rcar_data *data = dev->data;
223 	int ret;
224 
225 	/* Configure dt provided device signals when available */
226 	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
227 	if (ret < 0) {
228 		return ret;
229 	}
230 
231 	ret = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->mod_clk);
232 	if (ret < 0) {
233 		return ret;
234 	}
235 
236 	ret = clock_control_get_rate(config->clock_dev, (clock_control_subsys_t)&config->core_clk,
237 				     &data->clk_rate);
238 
239 	if (ret < 0) {
240 		return ret;
241 	}
242 
243 	return 0;
244 }
245 
246 static const struct pwm_driver_api pwm_rcar_driver_api = {
247 	.set_cycles = pwm_rcar_set_cycles,
248 	.get_cycles_per_sec = pwm_rcar_get_cycles_per_sec,
249 };
250 
251 /* Device Instantiation */
252 #define PWM_DEVICE_RCAR_INIT(n)                                                                    \
253 	PINCTRL_DT_INST_DEFINE(n);                                                                 \
254 	static const struct pwm_rcar_cfg pwm_rcar_cfg_##n = {                                      \
255 		.reg_addr = DT_INST_REG_ADDR(n),                                                   \
256 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),                                         \
257 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),                                \
258 		.mod_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module),                        \
259 		.mod_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain),                        \
260 		.core_clk.module = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, module),                       \
261 		.core_clk.domain = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain),                       \
262 	};                                                                                         \
263 	static struct pwm_rcar_data pwm_rcar_data_##n;                                             \
264 	DEVICE_DT_INST_DEFINE(n, pwm_rcar_init, NULL, &pwm_rcar_data_##n, &pwm_rcar_cfg_##n,       \
265 			      POST_KERNEL, CONFIG_PWM_INIT_PRIORITY,                               \
266 			      &pwm_rcar_driver_api);
267 
268 DT_INST_FOREACH_STATUS_OKAY(PWM_DEVICE_RCAR_INIT)
269