1 /*
2  * Copyright (c) 2023 SILA Embedded Solutions GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT maxim_max31790_pwm
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/mfd/max31790.h>
12 #include <zephyr/drivers/pwm.h>
13 #include <zephyr/drivers/pwm/max31790.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/logging/log.h>
18 
19 LOG_MODULE_REGISTER(pwm_max31790, CONFIG_PWM_LOG_LEVEL);
20 
21 struct max31790_pwm_config {
22 	struct i2c_dt_spec i2c;
23 };
24 
25 struct max31790_pwm_data {
26 	struct k_mutex lock;
27 };
28 
max31790_set_fandynamics_speedrange(uint8_t * destination,uint8_t value)29 static void max31790_set_fandynamics_speedrange(uint8_t *destination, uint8_t value)
30 {
31 	uint8_t length = MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH;
32 	uint8_t pos = MAX37190_FANXDYNAMICS_SPEEDRANGE_POS;
33 
34 	*destination &= ~GENMASK(pos + length - 1, pos);
35 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
36 }
37 
max31790_set_fandynamics_pwmrateofchange(uint8_t * destination,uint8_t value)38 static void max31790_set_fandynamics_pwmrateofchange(uint8_t *destination, uint8_t value)
39 {
40 	uint8_t length = MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH;
41 	uint8_t pos = MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_POS;
42 
43 	*destination &= ~GENMASK(pos + length - 1, pos);
44 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
45 }
46 
max31790_set_pwmfrequency(uint8_t * destination,uint8_t channel,uint8_t value)47 static void max31790_set_pwmfrequency(uint8_t *destination, uint8_t channel, uint8_t value)
48 {
49 	uint8_t length = MAX37190_PWMFREQUENCY_PWM_LENGTH;
50 	uint8_t pos = (channel / 3) * 4;
51 
52 	*destination &= ~GENMASK(pos + length - 1, pos);
53 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
54 }
55 
max31790_get_pwmfrequency(uint8_t value,uint8_t channel)56 static uint8_t max31790_get_pwmfrequency(uint8_t value, uint8_t channel)
57 {
58 	uint8_t length = MAX37190_PWMFREQUENCY_PWM_LENGTH;
59 	uint8_t pos = (channel / 3) * 4;
60 
61 	return FIELD_GET(GENMASK(pos + length - 1, pos), value);
62 }
63 
max31790_set_fanconfiguration_spinup(uint8_t * destination,uint8_t value)64 static void max31790_set_fanconfiguration_spinup(uint8_t *destination, uint8_t value)
65 {
66 	uint8_t length = MAX37190_FANXCONFIGURATION_SPINUP_LENGTH;
67 	uint8_t pos = MAX37190_FANXCONFIGURATION_SPINUP_POS;
68 
69 	*destination &= ~GENMASK(pos + length - 1, pos);
70 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
71 }
72 
max31790_convert_pwm_frequency_into_hz(uint16_t * result,uint8_t pwm_frequency)73 static bool max31790_convert_pwm_frequency_into_hz(uint16_t *result, uint8_t pwm_frequency)
74 {
75 	switch (pwm_frequency) {
76 	case 0:
77 		*result = 25;
78 		return true;
79 	case 1:
80 		*result = 30;
81 		return true;
82 	case 2:
83 		*result = 35;
84 		return true;
85 	case 3:
86 		*result = 100;
87 		return true;
88 	case 4:
89 		*result = 125;
90 		return true;
91 	case 5:
92 		*result = 150; /* actually 149.7, according to the datasheet */
93 		return true;
94 	case 6:
95 		*result = 1250;
96 		return true;
97 	case 7:
98 		*result = 1470;
99 		return true;
100 	case 8:
101 		*result = 3570;
102 		return true;
103 	case 9:
104 		*result = 5000;
105 		return true;
106 	case 10:
107 		*result = 12500;
108 		return true;
109 	case 11:
110 		*result = 25000;
111 		return true;
112 	default:
113 		LOG_ERR("invalid value %i for PWM frequency register", pwm_frequency);
114 		return false;
115 	}
116 }
117 
max31790_convert_pwm_frequency_into_register(uint8_t * result,uint32_t pwm_frequency)118 static bool max31790_convert_pwm_frequency_into_register(uint8_t *result, uint32_t pwm_frequency)
119 {
120 	switch (pwm_frequency) {
121 	case 25:
122 		*result = 0;
123 		return true;
124 	case 30:
125 		*result = 1;
126 		return true;
127 	case 35:
128 		*result = 2;
129 		return true;
130 	case 100:
131 		*result = 3;
132 		return true;
133 	case 125:
134 		*result = 4;
135 		return true;
136 	case 150: /* actually 149.7, according to the datasheet */
137 		*result = 5;
138 		return true;
139 	case 1250:
140 		*result = 6;
141 		return true;
142 	case 1470:
143 		*result = 7;
144 		return true;
145 	case 3570:
146 		*result = 8;
147 		return true;
148 	case 5000:
149 		*result = 9;
150 		return true;
151 	case 12500:
152 		*result = 10;
153 		return true;
154 	case 25000:
155 		*result = 11;
156 		return true;
157 	default:
158 		LOG_ERR("invalid value %i for PWM frequency in Hz", pwm_frequency);
159 		return false;
160 	}
161 }
162 
max31790_set_cycles_internal(const struct device * dev,uint32_t channel,uint32_t period_count,uint32_t pulse_count,pwm_flags_t flags)163 static int max31790_set_cycles_internal(const struct device *dev, uint32_t channel,
164 					uint32_t period_count, uint32_t pulse_count,
165 					pwm_flags_t flags)
166 {
167 	const struct max31790_pwm_config *config = dev->config;
168 	int result;
169 	uint8_t pwm_frequency_channel_value;
170 	uint8_t value_pwm_frequency;
171 	uint8_t value_fan_configuration;
172 	uint8_t value_fan_dynamics;
173 	uint8_t value_speed_range = MAX31790_FLAG_SPEED_RANGE_GET(flags);
174 	uint8_t value_pwm_rate_of_change = MAX31790_FLAG_PWM_RATE_OF_CHANGE_GET(flags);
175 	uint8_t buffer[3];
176 
177 	if (!max31790_convert_pwm_frequency_into_register(&pwm_frequency_channel_value,
178 							  period_count)) {
179 		return -EINVAL;
180 	}
181 
182 	result = i2c_reg_read_byte_dt(&config->i2c, MAX37190_REGISTER_PWMFREQUENCY,
183 				      &value_pwm_frequency);
184 	if (result != 0) {
185 		return result;
186 	}
187 
188 	max31790_set_pwmfrequency(&value_pwm_frequency, channel, pwm_frequency_channel_value);
189 
190 	result = i2c_reg_write_byte_dt(&config->i2c, MAX37190_REGISTER_PWMFREQUENCY,
191 				       value_pwm_frequency);
192 	if (result != 0) {
193 		return result;
194 	}
195 
196 	value_fan_configuration = 0;
197 	value_fan_dynamics = 0;
198 
199 	if (flags & PWM_MAX31790_FLAG_SPIN_UP) {
200 		max31790_set_fanconfiguration_spinup(&value_fan_configuration, 2);
201 	} else {
202 		max31790_set_fanconfiguration_spinup(&value_fan_configuration, 0);
203 	}
204 
205 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_MONITOR_BIT;
206 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_LOCKEDROTOR_BIT;
207 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_LOCKEDROTORPOLARITY_BIT;
208 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_TACH_BIT;
209 	value_fan_configuration |= MAX37190_FANXCONFIGURATION_TACHINPUTENABLED_BIT;
210 
211 	max31790_set_fandynamics_speedrange(&value_fan_dynamics, value_speed_range);
212 	max31790_set_fandynamics_pwmrateofchange(&value_fan_dynamics, value_pwm_rate_of_change);
213 	value_fan_dynamics |= MAX37190_FANXDYNAMICS_ASYMMETRICRATEOFCHANGE_BIT;
214 
215 	if ((flags & PWM_MAX31790_FLAG_RPM_MODE) == 0) {
216 		LOG_DBG("PWM mode");
217 		uint16_t tach_target_count = MAX31790_TACHTARGETCOUNT_MAXIMUM;
218 		value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_MODE_BIT;
219 		buffer[0] = MAX31790_REGISTER_TACHTARGETCOUNTMSB(channel);
220 		sys_put_be16(tach_target_count << 5, buffer + 1);
221 
222 		result = i2c_write_dt(&config->i2c, buffer, sizeof(buffer));
223 	} else {
224 		LOG_DBG("RPM mode");
225 		value_fan_configuration |= MAX37190_FANXCONFIGURATION_MODE_BIT;
226 		buffer[0] = MAX31790_REGISTER_TACHTARGETCOUNTMSB(channel);
227 		sys_put_be16(pulse_count << 5, buffer + 1);
228 
229 		result = i2c_write_dt(&config->i2c, buffer, sizeof(buffer));
230 	}
231 
232 	if (result != 0) {
233 		return result;
234 	}
235 
236 	result = i2c_reg_write_byte_dt(&config->i2c, MAX37190_REGISTER_FANCONFIGURATION(channel),
237 				       value_fan_configuration);
238 	if (result != 0) {
239 		return result;
240 	}
241 
242 	result = i2c_reg_write_byte_dt(&config->i2c, MAX31790_REGISTER_FANDYNAMICS(channel),
243 				       value_fan_dynamics);
244 	if (result != 0) {
245 		return result;
246 	}
247 
248 	if ((flags & PWM_MAX31790_FLAG_RPM_MODE) == 0) {
249 		uint16_t pwm_target_duty_cycle =
250 			pulse_count * MAX31790_PWMTARGETDUTYCYCLE_MAXIMUM / period_count;
251 		buffer[0] = MAX31790_REGISTER_PWMOUTTARGETDUTYCYCLEMSB(channel);
252 		sys_put_be16(pwm_target_duty_cycle << 7, buffer + 1);
253 
254 		result = i2c_write_dt(&config->i2c, buffer, sizeof(buffer));
255 		if (result != 0) {
256 			return result;
257 		}
258 	}
259 
260 	return 0;
261 }
262 
max31790_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_count,uint32_t pulse_count,pwm_flags_t flags)263 static int max31790_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_count,
264 			       uint32_t pulse_count, pwm_flags_t flags)
265 {
266 	struct max31790_pwm_data *data = dev->data;
267 	int result;
268 
269 	LOG_DBG("set period %i with pulse %i for channel %i and flags 0x%04X", period_count,
270 		pulse_count, channel, flags);
271 
272 	if (channel > MAX31790_CHANNEL_COUNT) {
273 		LOG_ERR("invalid channel number %i", channel);
274 		return -EINVAL;
275 	}
276 
277 	if (period_count == 0) {
278 		LOG_ERR("period count must be > 0");
279 		return -EINVAL;
280 	}
281 
282 	k_mutex_lock(&data->lock, K_FOREVER);
283 	result = max31790_set_cycles_internal(dev, channel, period_count, pulse_count, flags);
284 	k_mutex_unlock(&data->lock);
285 	return result;
286 }
287 
max31790_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)288 static int max31790_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles)
289 {
290 	const struct max31790_pwm_config *config = dev->config;
291 	struct max31790_pwm_data *data = dev->data;
292 	int result;
293 	bool success;
294 	uint8_t pwm_frequency_register;
295 	uint8_t pwm_frequency = 1;
296 	uint16_t pwm_frequency_in_hz;
297 
298 	if (channel > MAX31790_CHANNEL_COUNT) {
299 		LOG_ERR("invalid channel number %i", channel);
300 		return -EINVAL;
301 	}
302 
303 	k_mutex_lock(&data->lock, K_FOREVER);
304 	result = i2c_reg_read_byte_dt(&config->i2c, MAX37190_REGISTER_GLOBALCONFIGURATION,
305 				      &pwm_frequency_register);
306 	if (result != 0) {
307 		k_mutex_unlock(&data->lock);
308 		return result;
309 	}
310 
311 	pwm_frequency = max31790_get_pwmfrequency(pwm_frequency_register, channel);
312 	success = max31790_convert_pwm_frequency_into_hz(&pwm_frequency_in_hz, pwm_frequency);
313 	if (!success) {
314 		k_mutex_unlock(&data->lock);
315 		return -EINVAL;
316 	}
317 
318 	*cycles = pwm_frequency_in_hz;
319 
320 	k_mutex_unlock(&data->lock);
321 	return 0;
322 }
323 
324 static DEVICE_API(pwm, max31790_pwm_api) = {
325 	.set_cycles = max31790_set_cycles,
326 	.get_cycles_per_sec = max31790_get_cycles_per_sec,
327 };
328 
max31790_pwm_init(const struct device * dev)329 static int max31790_pwm_init(const struct device *dev)
330 {
331 	const struct max31790_pwm_config *config = dev->config;
332 	struct max31790_pwm_data *data = dev->data;
333 
334 	k_mutex_init(&data->lock);
335 
336 	if (!i2c_is_ready_dt(&config->i2c)) {
337 		LOG_ERR("I2C device not ready");
338 		return -ENODEV;
339 	}
340 
341 	return 0;
342 }
343 
344 #define MAX31790_PWM_INIT(inst)                                                                    \
345 	static const struct max31790_pwm_config max31790_pwm_##inst##_config = {                   \
346 		.i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)),                                      \
347 	};                                                                                         \
348                                                                                                    \
349 	static struct max31790_pwm_data max31790_pwm_##inst##_data;                                \
350                                                                                                    \
351 	DEVICE_DT_INST_DEFINE(inst, max31790_pwm_init, NULL, &max31790_pwm_##inst##_data,          \
352 			      &max31790_pwm_##inst##_config, POST_KERNEL,                          \
353 			      CONFIG_PWM_INIT_PRIORITY, &max31790_pwm_api);
354 
355 DT_INST_FOREACH_STATUS_OKAY(MAX31790_PWM_INIT);
356