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
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/pwm.h>
12 #include <zephyr/drivers/pwm/max31790.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16 
17 LOG_MODULE_REGISTER(pwm_max31790, CONFIG_PWM_LOG_LEVEL);
18 
19 #define MAX31790_OSCILLATOR_FREQUENCY_IN_HZ 32768
20 #define MAX31790_PWMTARGETDUTYCYCLE_MAXIMUM ((1 << 9) - 1)
21 #define MAX31790_CHANNEL_COUNT              6
22 
23 struct max31790_config {
24 	struct i2c_dt_spec i2c;
25 };
26 
27 struct max31790_data {
28 	struct k_mutex lock;
29 };
30 
31 #define MAX37190_REGISTER_GLOBALCONFIGURATION               0x00
32 #define MAX37190_REGISTER_PWMFREQUENCY                      0x01
33 #define MAX37190_REGISTER_FANCONFIGURATION(channel)         (0x02 + channel)
34 #define MAX31790_REGISTER_PWMOUTTARGETDUTYCYCLEMSB(channel) (0x40 + 2 * channel)
35 #define MAX31790_REGISTER_FANDYNAMICS(channel)              (0x08 + channel)
36 #define MAX31790_REGISTER_TACHTARGETCOUNTMSB(channel)       (0x50 + 2 * channel)
37 
38 #define MAX37190_GLOBALCONFIGURATION_STANDBY_BIT           BIT(7)
39 #define MAX37190_FANXCONFIGURATION_MONITOR_BIT             BIT(4)
40 #define MAX37190_FANXCONFIGURATION_TACHINPUTENABLED_BIT    BIT(3)
41 #define MAX37190_FANXCONFIGURATION_LOCKEDROTOR_BIT         BIT(2)
42 #define MAX37190_FANXCONFIGURATION_LOCKEDROTORPOLARITY_BIT BIT(1)
43 #define MAX37190_FANXCONFIGURATION_TACH_BIT                BIT(0)
44 #define MAX37190_FANXCONFIGURATION_MODE_BIT                BIT(7)
45 #define MAX37190_FANXDYNAMICS_ASYMMETRICRATEOFCHANGE_BIT   BIT(1)
46 
47 #define MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH      3
48 #define MAX37190_FANXDYNAMICS_SPEEDRANGE_POS         5
49 #define MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH 3
50 #define MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_POS    2
51 #define MAX37190_PWMFREQUENCY_PWM_LENGTH             4
52 #define MAX37190_PWMFREQUENCY_PWM4TO6_POS            4
53 #define MAX37190_PWMFREQUENCY_PWM1TO3_LENGTH         4
54 #define MAX37190_PWMFREQUENCY_PWM1TO3_POS            0
55 #define MAX37190_FANXCONFIGURATION_SPINUP_LENGTH     2
56 #define MAX37190_FANXCONFIGURATION_SPINUP_POS        5
57 
58 #define PWM_MAX31790_FLAG_SPEED_RANGE_GET(flags)                                                   \
59 	FIELD_GET(GENMASK(MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH +                                \
60 				  PWM_MAX31790_FLAG_SPEED_RANGE_POS - 1,                           \
61 			  PWM_MAX31790_FLAG_SPEED_RANGE_POS),                                      \
62 		  flags)
63 #define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_GET(flags)                                            \
64 	FIELD_GET(GENMASK(MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH +                           \
65 				  PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS - 1,                    \
66 			  PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS),                               \
67 		  flags)
68 
max31790_set_fandynamics_speedrange(uint8_t * destination,uint8_t value)69 static void max31790_set_fandynamics_speedrange(uint8_t *destination, uint8_t value)
70 {
71 	uint8_t length = MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH;
72 	uint8_t pos = MAX37190_FANXDYNAMICS_SPEEDRANGE_POS;
73 
74 	*destination &= ~GENMASK(pos + length - 1, pos);
75 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
76 }
77 
max31790_set_fandynamics_pwmrateofchange(uint8_t * destination,uint8_t value)78 static void max31790_set_fandynamics_pwmrateofchange(uint8_t *destination, uint8_t value)
79 {
80 	uint8_t length = MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH;
81 	uint8_t pos = MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_POS;
82 
83 	*destination &= ~GENMASK(pos + length - 1, pos);
84 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
85 }
86 
max31790_set_pwmfrequency(uint8_t * destination,uint8_t channel,uint8_t value)87 static void max31790_set_pwmfrequency(uint8_t *destination, uint8_t channel, uint8_t value)
88 {
89 	uint8_t length = MAX37190_PWMFREQUENCY_PWM_LENGTH;
90 	uint8_t pos = (channel / 3) * 4;
91 
92 	*destination &= ~GENMASK(pos + length - 1, pos);
93 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
94 }
95 
max31790_get_pwmfrequency(uint8_t value,uint8_t channel)96 static uint8_t max31790_get_pwmfrequency(uint8_t value, uint8_t channel)
97 {
98 	uint8_t length = MAX37190_PWMFREQUENCY_PWM_LENGTH;
99 	uint8_t pos = (channel / 3) * 4;
100 
101 	return FIELD_GET(GENMASK(pos + length - 1, pos), value);
102 }
103 
max31790_set_fanconfiguration_spinup(uint8_t * destination,uint8_t value)104 static void max31790_set_fanconfiguration_spinup(uint8_t *destination, uint8_t value)
105 {
106 	uint8_t length = MAX37190_FANXCONFIGURATION_SPINUP_LENGTH;
107 	uint8_t pos = MAX37190_FANXCONFIGURATION_SPINUP_POS;
108 
109 	*destination &= ~GENMASK(pos + length - 1, pos);
110 	*destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value);
111 }
112 
max31790_read_register(const struct device * dev,uint8_t address,uint8_t * value)113 static int max31790_read_register(const struct device *dev, uint8_t address, uint8_t *value)
114 {
115 	const struct max31790_config *config = dev->config;
116 	int result;
117 
118 	result = i2c_reg_read_byte_dt(&config->i2c, address, value);
119 	if (result != 0) {
120 		LOG_ERR("unable to read register 0x%02X, error %i", address, result);
121 	}
122 
123 	LOG_DBG("read value 0x%02X from register 0x%02X", *value, address);
124 
125 	return result;
126 }
127 
max31790_write_register_uint8(const struct device * dev,uint8_t address,uint8_t value)128 static int max31790_write_register_uint8(const struct device *dev, uint8_t address, uint8_t value)
129 {
130 	const struct max31790_config *config = dev->config;
131 	int result;
132 
133 	LOG_DBG("writing value 0x%02X to register 0x%02X", value, address);
134 	result = i2c_reg_write_byte_dt(&config->i2c, address, value);
135 	if (result != 0) {
136 		LOG_ERR("unable to write register 0x%02X, error %i", address, result);
137 	}
138 
139 	return result;
140 }
141 
max31790_write_register_uint16(const struct device * dev,uint8_t address,uint16_t value)142 static int max31790_write_register_uint16(const struct device *dev, uint8_t address, uint16_t value)
143 {
144 	const struct max31790_config *config = dev->config;
145 	int result;
146 	uint8_t buffer[] = {
147 		address,
148 		value >> 8,
149 		value,
150 	};
151 
152 	LOG_DBG("writing value 0x%04X to address 0x%02X", value, address);
153 	result = i2c_write_dt(&config->i2c, buffer, sizeof(buffer));
154 	if (result != 0) {
155 		LOG_ERR("unable to write to address 0x%02X, error %i", address, result);
156 	}
157 
158 	return result;
159 }
160 
max31790_convert_pwm_frequency_into_hz(uint16_t * result,uint8_t pwm_frequency)161 static bool max31790_convert_pwm_frequency_into_hz(uint16_t *result, uint8_t pwm_frequency)
162 {
163 	switch (pwm_frequency) {
164 	case 0:
165 		*result = 25;
166 		return true;
167 	case 1:
168 		*result = 30;
169 		return true;
170 	case 2:
171 		*result = 35;
172 		return true;
173 	case 3:
174 		*result = 100;
175 		return true;
176 	case 4:
177 		*result = 125;
178 		return true;
179 	case 5:
180 		*result = 150; /* actually 149.7, according to the datasheet */
181 		return true;
182 	case 6:
183 		*result = 1250;
184 		return true;
185 	case 7:
186 		*result = 1470;
187 		return true;
188 	case 8:
189 		*result = 3570;
190 		return true;
191 	case 9:
192 		*result = 5000;
193 		return true;
194 	case 10:
195 		*result = 12500;
196 		return true;
197 	case 11:
198 		*result = 25000;
199 		return true;
200 	default:
201 		LOG_ERR("invalid value %i for PWM frequency register", pwm_frequency);
202 		return false;
203 	}
204 }
205 
max31790_convert_pwm_frequency_into_register(uint8_t * result,uint32_t pwm_frequency)206 static bool max31790_convert_pwm_frequency_into_register(uint8_t *result, uint32_t pwm_frequency)
207 {
208 	switch (pwm_frequency) {
209 	case 25:
210 		*result = 0;
211 		return true;
212 	case 30:
213 		*result = 1;
214 		return true;
215 	case 35:
216 		*result = 2;
217 		return true;
218 	case 100:
219 		*result = 3;
220 		return true;
221 	case 125:
222 		*result = 4;
223 		return true;
224 	case 150: /* actually 149.7, according to the datasheet */
225 		*result = 5;
226 		return true;
227 	case 1250:
228 		*result = 6;
229 		return true;
230 	case 1470:
231 		*result = 7;
232 		return true;
233 	case 3570:
234 		*result = 8;
235 		return true;
236 	case 5000:
237 		*result = 9;
238 		return true;
239 	case 12500:
240 		*result = 10;
241 		return true;
242 	case 25000:
243 		*result = 11;
244 		return true;
245 	default:
246 		LOG_ERR("invalid value %i for PWM frequency in Hz", pwm_frequency);
247 		return false;
248 	}
249 }
250 
max31790_set_cycles_internal(const struct device * dev,uint32_t channel,uint32_t period_count,uint32_t pulse_count,pwm_flags_t flags)251 static int max31790_set_cycles_internal(const struct device *dev, uint32_t channel,
252 					uint32_t period_count, uint32_t pulse_count,
253 					pwm_flags_t flags)
254 {
255 	int result;
256 	uint8_t pwm_frequency_channel_value;
257 	uint8_t value_pwm_frequency;
258 	uint8_t value_fan_configuration;
259 	uint8_t value_fan_dynamics;
260 	uint8_t value_speed_range = PWM_MAX31790_FLAG_SPEED_RANGE_GET(flags);
261 	uint8_t value_pwm_rate_of_change = PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_GET(flags);
262 
263 	if (!max31790_convert_pwm_frequency_into_register(&pwm_frequency_channel_value,
264 							  period_count)) {
265 		return -EINVAL;
266 	}
267 
268 	result = max31790_read_register(dev, MAX37190_REGISTER_PWMFREQUENCY, &value_pwm_frequency);
269 	if (result != 0) {
270 		return result;
271 	}
272 
273 	max31790_set_pwmfrequency(&value_pwm_frequency, channel, pwm_frequency_channel_value);
274 
275 	result = max31790_write_register_uint8(dev, MAX37190_REGISTER_PWMFREQUENCY,
276 					       value_pwm_frequency);
277 	if (result != 0) {
278 		return result;
279 	}
280 
281 	value_fan_configuration = 0;
282 	value_fan_dynamics = 0;
283 
284 	if (flags & PWM_MAX31790_FLAG_SPIN_UP) {
285 		max31790_set_fanconfiguration_spinup(&value_fan_configuration, 2);
286 	} else {
287 		max31790_set_fanconfiguration_spinup(&value_fan_configuration, 0);
288 	}
289 
290 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_MONITOR_BIT;
291 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_LOCKEDROTOR_BIT;
292 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_LOCKEDROTORPOLARITY_BIT;
293 	value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_TACH_BIT;
294 	value_fan_configuration |= MAX37190_FANXCONFIGURATION_TACHINPUTENABLED_BIT;
295 
296 	max31790_set_fandynamics_speedrange(&value_fan_dynamics, value_speed_range);
297 	max31790_set_fandynamics_pwmrateofchange(&value_fan_dynamics, value_pwm_rate_of_change);
298 	value_fan_dynamics |= MAX37190_FANXDYNAMICS_ASYMMETRICRATEOFCHANGE_BIT;
299 
300 	if ((flags & PWM_MAX31790_FLAG_RPM_MODE) == 0) {
301 		LOG_DBG("PWM mode");
302 		uint16_t pwm_target_duty_cycle =
303 			pulse_count * MAX31790_PWMTARGETDUTYCYCLE_MAXIMUM / period_count;
304 		value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_MODE_BIT;
305 
306 		result = max31790_write_register_uint16(
307 			dev, MAX31790_REGISTER_PWMOUTTARGETDUTYCYCLEMSB(channel),
308 			pwm_target_duty_cycle);
309 		if (result != 0) {
310 			return result;
311 		}
312 	} else {
313 		LOG_DBG("RPM mode");
314 		value_fan_configuration |= MAX37190_FANXCONFIGURATION_MODE_BIT;
315 
316 		result = max31790_write_register_uint16(
317 			dev, MAX31790_REGISTER_TACHTARGETCOUNTMSB(channel), pulse_count);
318 		if (result != 0) {
319 			return result;
320 		}
321 	}
322 
323 	result = max31790_write_register_uint8(dev, MAX37190_REGISTER_FANCONFIGURATION(channel),
324 					       value_fan_configuration);
325 	if (result != 0) {
326 		return result;
327 	}
328 
329 	result = max31790_write_register_uint8(dev, MAX31790_REGISTER_FANDYNAMICS(channel),
330 					       value_fan_dynamics);
331 	if (result != 0) {
332 		return result;
333 	}
334 
335 	return 0;
336 }
337 
max31790_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_count,uint32_t pulse_count,pwm_flags_t flags)338 static int max31790_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_count,
339 			       uint32_t pulse_count, pwm_flags_t flags)
340 {
341 	struct max31790_data *data = dev->data;
342 	int result;
343 
344 	LOG_DBG("set period %i with pulse %i for channel %i and flags 0x%04X", period_count,
345 		pulse_count, channel, flags);
346 
347 	if (channel > MAX31790_CHANNEL_COUNT) {
348 		LOG_ERR("invalid channel number %i", channel);
349 		return -EINVAL;
350 	}
351 
352 	if (period_count == 0) {
353 		LOG_ERR("period count must be > 0");
354 		return -EINVAL;
355 	}
356 
357 	k_mutex_lock(&data->lock, K_FOREVER);
358 	result = max31790_set_cycles_internal(dev, channel, period_count, pulse_count, flags);
359 	k_mutex_unlock(&data->lock);
360 	return result;
361 }
362 
max31790_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)363 static int max31790_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles)
364 {
365 	struct max31790_data *data = dev->data;
366 	int result;
367 	bool success;
368 	uint8_t pwm_frequency_register;
369 	uint8_t pwm_frequency = 1;
370 	uint16_t pwm_frequency_in_hz;
371 
372 	if (channel > MAX31790_CHANNEL_COUNT) {
373 		LOG_ERR("invalid channel number %i", channel);
374 		return -EINVAL;
375 	}
376 
377 	k_mutex_lock(&data->lock, K_FOREVER);
378 	result = max31790_read_register(dev, MAX37190_REGISTER_GLOBALCONFIGURATION,
379 					&pwm_frequency_register);
380 
381 	if (result != 0) {
382 		k_mutex_unlock(&data->lock);
383 		return result;
384 	}
385 
386 	pwm_frequency = max31790_get_pwmfrequency(pwm_frequency_register, channel);
387 	success = max31790_convert_pwm_frequency_into_hz(&pwm_frequency_in_hz, pwm_frequency);
388 
389 	if (!success) {
390 		k_mutex_unlock(&data->lock);
391 		return -EINVAL;
392 	}
393 
394 	*cycles = pwm_frequency_in_hz;
395 
396 	k_mutex_unlock(&data->lock);
397 	return 0;
398 }
399 
400 static const struct pwm_driver_api max31790_api = {
401 	.set_cycles = max31790_set_cycles,
402 	.get_cycles_per_sec = max31790_get_cycles_per_sec,
403 };
404 
max31790_init(const struct device * dev)405 static int max31790_init(const struct device *dev)
406 {
407 	const struct max31790_config *config = dev->config;
408 	struct max31790_data *data = dev->data;
409 	int result;
410 	uint8_t reg_value;
411 
412 	k_mutex_init(&data->lock);
413 
414 	if (!i2c_is_ready_dt(&config->i2c)) {
415 		LOG_ERR("I2C device not ready");
416 		return -ENODEV;
417 	}
418 
419 	result = max31790_read_register(dev, MAX37190_REGISTER_GLOBALCONFIGURATION, &reg_value);
420 	if (result != 0) {
421 		return result;
422 	}
423 
424 	if ((reg_value & MAX37190_GLOBALCONFIGURATION_STANDBY_BIT) != 0) {
425 		LOG_DBG("taking PWM controller out of standby");
426 
427 		reg_value &= ~MAX37190_GLOBALCONFIGURATION_STANDBY_BIT;
428 		result = max31790_write_register_uint8(dev, MAX37190_REGISTER_GLOBALCONFIGURATION,
429 						       reg_value);
430 		if (result != 0) {
431 			return result;
432 		}
433 
434 		result = max31790_read_register(dev, MAX37190_REGISTER_GLOBALCONFIGURATION,
435 						&reg_value);
436 		if (result != 0) {
437 			return result;
438 		}
439 
440 		if ((reg_value & MAX37190_GLOBALCONFIGURATION_STANDBY_BIT) != 0) {
441 			LOG_ERR("unable to take PWM controller out of standby");
442 			return -ENODEV;
443 		}
444 	}
445 
446 	return 0;
447 }
448 
449 #define MAX31790_INIT(inst)                                                                        \
450 	static const struct max31790_config max31790_##inst##_config = {                           \
451 		.i2c = I2C_DT_SPEC_INST_GET(inst),                                                 \
452 	};                                                                                         \
453                                                                                                    \
454 	static struct max31790_data max31790_##inst##_data;                                        \
455                                                                                                    \
456 	DEVICE_DT_INST_DEFINE(inst, max31790_init, NULL, &max31790_##inst##_data,                  \
457 			      &max31790_##inst##_config, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY,    \
458 			      &max31790_api);
459 
460 DT_INST_FOREACH_STATUS_OKAY(MAX31790_INIT);
461