1 /*
2  * Copyright (c) 2018 SiFive Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT sifive_pwm0
8 
9 #include <zephyr/arch/cpu.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/sys_io.h>
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/pinctrl.h>
14 #include <zephyr/drivers/pwm.h>
15 #include <soc.h>
16 
17 LOG_MODULE_REGISTER(pwm_sifive, CONFIG_PWM_LOG_LEVEL);
18 
19 /* Macros */
20 
21 #define PWM_REG(z_config, _offset) ((mem_addr_t) ((z_config)->base + _offset))
22 
23 /* Register Offsets */
24 #define REG_PWMCFG		0x00
25 #define REG_PWMCOUNT		0x08
26 #define REG_PWMS		0x10
27 #define REG_PWMCMP0		0x20
28 #define REG_PWMCMP(_channel)	(REG_PWMCMP0 + ((_channel) * 0x4))
29 
30 /* Number of PWM Channels */
31 #define SF_NUMCHANNELS		4
32 
33 /* pwmcfg Bit Offsets */
34 #define SF_PWMSTICKY			8
35 #define SF_PWMZEROCMP			9
36 #define SF_PWMDEGLITCH			10
37 #define SF_PWMENALWAYS			12
38 #define SF_PWMENONESHOT			13
39 #define SF_PWMCMPCENTER(_channel)	(16 + (_channel))
40 #define SF_PWMCMPGANG(_channel)		(24 + (_channel))
41 #define SF_PWMCMPIP(_channel)		(28 + (_channel))
42 
43 /* pwmcount scale factor */
44 #define SF_PWMSCALEMASK		0xF
45 #define SF_PWMSCALE(_val)	(SF_PWMSCALEMASK & (_val))
46 
47 #define SF_PWMCOUNT_MIN_WIDTH	15
48 
49 /* Structure Declarations */
50 
51 struct pwm_sifive_data {};
52 
53 struct pwm_sifive_cfg {
54 	uint32_t base;
55 	uint32_t f_sys;
56 	uint32_t cmpwidth;
57 	const struct pinctrl_dev_config *pcfg;
58 };
59 
60 /* Helper Functions */
61 
sys_set_mask(mem_addr_t addr,uint32_t mask,uint32_t value)62 static inline void sys_set_mask(mem_addr_t addr, uint32_t mask, uint32_t value)
63 {
64 	uint32_t temp = sys_read32(addr);
65 
66 	temp &= ~(mask);
67 	temp |= value;
68 
69 	sys_write32(temp, addr);
70 }
71 
72 /* API Functions */
73 
pwm_sifive_init(const struct device * dev)74 static int pwm_sifive_init(const struct device *dev)
75 {
76 	const struct pwm_sifive_cfg *config = dev->config;
77 #ifdef CONFIG_PINCTRL
78 	int ret;
79 
80 	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
81 	if (ret < 0) {
82 		return ret;
83 	}
84 #endif
85 
86 	/* When pwms == pwmcmp0, reset the counter */
87 	sys_set_bit(PWM_REG(config, REG_PWMCFG), SF_PWMZEROCMP);
88 
89 	/* Enable continuous operation */
90 	sys_set_bit(PWM_REG(config, REG_PWMCFG), SF_PWMENALWAYS);
91 
92 	/* Clear IP config bits */
93 	sys_clear_bit(PWM_REG(config, REG_PWMCFG), SF_PWMSTICKY);
94 	sys_clear_bit(PWM_REG(config, REG_PWMCFG), SF_PWMDEGLITCH);
95 
96 	/* Clear all channels */
97 	for (int i = 0; i < SF_NUMCHANNELS; i++) {
98 		/* Clear the channel comparator */
99 		sys_write32(0, PWM_REG(config, REG_PWMCMP(i)));
100 
101 		/* Clear the compare center and compare gang bits */
102 		sys_clear_bit(PWM_REG(config, REG_PWMCFG), SF_PWMCMPCENTER(i));
103 		sys_clear_bit(PWM_REG(config, REG_PWMCFG), SF_PWMCMPGANG(i));
104 	}
105 
106 	return 0;
107 }
108 
pwm_sifive_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)109 static int pwm_sifive_set_cycles(const struct device *dev, uint32_t channel,
110 				 uint32_t period_cycles, uint32_t pulse_cycles,
111 				 pwm_flags_t flags)
112 {
113 	const struct pwm_sifive_cfg *config = dev->config;
114 	uint32_t count_max = 0U;
115 	uint32_t max_cmp_val = 0U;
116 	uint32_t pwmscale = 0U;
117 
118 	if (flags) {
119 		/* PWM polarity not supported (yet?) */
120 		return -ENOTSUP;
121 	}
122 
123 	if (channel >= SF_NUMCHANNELS) {
124 		LOG_ERR("The requested PWM channel %d is invalid\n", channel);
125 		return -EINVAL;
126 	}
127 
128 	/* Channel 0 sets the period, we can't output PWM with it */
129 	if (channel == 0U) {
130 		LOG_ERR("PWM channel 0 cannot be configured\n");
131 		return -ENOTSUP;
132 	}
133 
134 	/* We can't support periods greater than we can store in pwmcount */
135 	count_max = (1 << (config->cmpwidth + SF_PWMCOUNT_MIN_WIDTH)) - 1;
136 
137 	if (period_cycles > count_max) {
138 		LOG_ERR("Requested period is %d but maximum is %d\n",
139 			period_cycles, count_max);
140 		return -EIO;
141 	}
142 
143 	/* Calculate the maximum value that pwmcmpX can be set to */
144 	max_cmp_val = ((1 << config->cmpwidth) - 1);
145 
146 	/*
147 	 * Find the minimum value of pwmscale that will allow us to set the
148 	 * requested period
149 	 */
150 	while ((period_cycles >> pwmscale) > max_cmp_val) {
151 		pwmscale++;
152 	}
153 
154 	/* Make sure that we can scale that much */
155 	if (pwmscale > SF_PWMSCALEMASK) {
156 		LOG_ERR("Requested period is %d but maximum is %d\n",
157 			period_cycles, max_cmp_val << pwmscale);
158 		return -EIO;
159 	}
160 
161 	/* Set the pwmscale field */
162 	sys_set_mask(PWM_REG(config, REG_PWMCFG),
163 		     SF_PWMSCALEMASK,
164 		     SF_PWMSCALE(pwmscale));
165 
166 	/* Set the period by setting pwmcmp0 */
167 	sys_write32((period_cycles >> pwmscale), PWM_REG(config, REG_PWMCMP0));
168 
169 	/* Set the duty cycle by setting pwmcmpX */
170 	sys_write32((pulse_cycles >> pwmscale),
171 		    PWM_REG(config, REG_PWMCMP(channel)));
172 
173 	LOG_DBG("channel: %d, pwmscale: %d, pwmcmp0: %d, pwmcmp%d: %d",
174 		channel,
175 		pwmscale,
176 		(period_cycles >> pwmscale),
177 		channel,
178 		(pulse_cycles >> pwmscale));
179 
180 	return 0;
181 }
182 
pwm_sifive_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)183 static int pwm_sifive_get_cycles_per_sec(const struct device *dev,
184 					 uint32_t channel, uint64_t *cycles)
185 {
186 	const struct pwm_sifive_cfg *config;
187 
188 	if (dev == NULL) {
189 		LOG_ERR("The device instance pointer was NULL\n");
190 		return -EFAULT;
191 	}
192 
193 	config = dev->config;
194 	if (config == NULL) {
195 		LOG_ERR("The device configuration is NULL\n");
196 		return -EFAULT;
197 	}
198 
199 	/* Fail if we don't have that channel */
200 	if (channel >= SF_NUMCHANNELS) {
201 		return -EINVAL;
202 	}
203 
204 	*cycles = config->f_sys;
205 
206 	return 0;
207 }
208 
209 /* Device Instantiation */
210 
211 static const struct pwm_driver_api pwm_sifive_api = {
212 	.set_cycles = pwm_sifive_set_cycles,
213 	.get_cycles_per_sec = pwm_sifive_get_cycles_per_sec,
214 };
215 
216 #define PWM_SIFIVE_INIT(n)	\
217 	PINCTRL_DT_INST_DEFINE(n);	\
218 	static struct pwm_sifive_data pwm_sifive_data_##n;	\
219 	static const struct pwm_sifive_cfg pwm_sifive_cfg_##n = {	\
220 			.base = DT_INST_REG_ADDR(n),	\
221 			.f_sys = SIFIVE_PERIPHERAL_CLOCK_FREQUENCY,  \
222 			.cmpwidth = DT_INST_PROP(n, sifive_compare_width), \
223 			.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),	\
224 		};	\
225 	DEVICE_DT_INST_DEFINE(n,	\
226 			    pwm_sifive_init,	\
227 			    NULL,	\
228 			    &pwm_sifive_data_##n,	\
229 			    &pwm_sifive_cfg_##n,	\
230 			    POST_KERNEL,	\
231 			    CONFIG_PWM_INIT_PRIORITY,	\
232 			    &pwm_sifive_api);
233 
234 DT_INST_FOREACH_STATUS_OKAY(PWM_SIFIVE_INIT)
235