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