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, ®_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 ®_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