| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * max31790.c - Part of lm_sensors, Linux kernel modules for hardware |
|---|
| 3 | 4 | * monitoring. |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * (C) 2015 by Il Han <corone.il.han@gmail.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 9 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 10 | | - * (at your option) any later version. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | 7 | */ |
|---|
| 17 | 8 | |
|---|
| 18 | 9 | #include <linux/err.h> |
|---|
| .. | .. |
|---|
| 36 | 27 | |
|---|
| 37 | 28 | /* Fan Config register bits */ |
|---|
| 38 | 29 | #define MAX31790_FAN_CFG_RPM_MODE 0x80 |
|---|
| 30 | +#define MAX31790_FAN_CFG_CTRL_MON 0x10 |
|---|
| 39 | 31 | #define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08 |
|---|
| 40 | 32 | #define MAX31790_FAN_CFG_TACH_INPUT 0x01 |
|---|
| 41 | 33 | |
|---|
| .. | .. |
|---|
| 113 | 105 | data->tach[NR_CHANNEL + i] = rv; |
|---|
| 114 | 106 | } else { |
|---|
| 115 | 107 | rv = i2c_smbus_read_word_swapped(client, |
|---|
| 116 | | - MAX31790_REG_PWMOUT(i)); |
|---|
| 108 | + MAX31790_REG_PWM_DUTY_CYCLE(i)); |
|---|
| 117 | 109 | if (rv < 0) |
|---|
| 118 | 110 | goto abort; |
|---|
| 119 | 111 | data->pwm[i] = rv; |
|---|
| .. | .. |
|---|
| 252 | 244 | case hwmon_fan_fault: |
|---|
| 253 | 245 | if (channel < NR_CHANNEL || |
|---|
| 254 | 246 | (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) |
|---|
| 255 | | - return S_IRUGO; |
|---|
| 247 | + return 0444; |
|---|
| 256 | 248 | return 0; |
|---|
| 257 | 249 | case hwmon_fan_target: |
|---|
| 258 | 250 | if (channel < NR_CHANNEL && |
|---|
| 259 | 251 | !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) |
|---|
| 260 | | - return S_IRUGO | S_IWUSR; |
|---|
| 252 | + return 0644; |
|---|
| 261 | 253 | return 0; |
|---|
| 262 | 254 | default: |
|---|
| 263 | 255 | return 0; |
|---|
| .. | .. |
|---|
| 280 | 272 | *val = data->pwm[channel] >> 8; |
|---|
| 281 | 273 | return 0; |
|---|
| 282 | 274 | case hwmon_pwm_enable: |
|---|
| 283 | | - if (fan_config & MAX31790_FAN_CFG_RPM_MODE) |
|---|
| 284 | | - *val = 2; |
|---|
| 285 | | - else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN) |
|---|
| 286 | | - *val = 1; |
|---|
| 287 | | - else |
|---|
| 275 | + if (fan_config & MAX31790_FAN_CFG_CTRL_MON) |
|---|
| 288 | 276 | *val = 0; |
|---|
| 277 | + else if (fan_config & MAX31790_FAN_CFG_RPM_MODE) |
|---|
| 278 | + *val = 2; |
|---|
| 279 | + else |
|---|
| 280 | + *val = 1; |
|---|
| 289 | 281 | return 0; |
|---|
| 290 | 282 | default: |
|---|
| 291 | 283 | return -EOPNOTSUPP; |
|---|
| .. | .. |
|---|
| 308 | 300 | err = -EINVAL; |
|---|
| 309 | 301 | break; |
|---|
| 310 | 302 | } |
|---|
| 311 | | - data->pwm[channel] = val << 8; |
|---|
| 303 | + data->valid = false; |
|---|
| 312 | 304 | err = i2c_smbus_write_word_swapped(client, |
|---|
| 313 | 305 | MAX31790_REG_PWMOUT(channel), |
|---|
| 314 | | - data->pwm[channel]); |
|---|
| 306 | + val << 8); |
|---|
| 315 | 307 | break; |
|---|
| 316 | 308 | case hwmon_pwm_enable: |
|---|
| 317 | 309 | fan_config = data->fan_config[channel]; |
|---|
| 318 | 310 | if (val == 0) { |
|---|
| 319 | | - fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN | |
|---|
| 320 | | - MAX31790_FAN_CFG_RPM_MODE); |
|---|
| 311 | + fan_config |= MAX31790_FAN_CFG_CTRL_MON; |
|---|
| 312 | + /* |
|---|
| 313 | + * Disable RPM mode; otherwise disabling fan speed |
|---|
| 314 | + * monitoring is not possible. |
|---|
| 315 | + */ |
|---|
| 316 | + fan_config &= ~MAX31790_FAN_CFG_RPM_MODE; |
|---|
| 321 | 317 | } else if (val == 1) { |
|---|
| 322 | | - fan_config = (fan_config | |
|---|
| 323 | | - MAX31790_FAN_CFG_TACH_INPUT_EN) & |
|---|
| 324 | | - ~MAX31790_FAN_CFG_RPM_MODE; |
|---|
| 318 | + fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE); |
|---|
| 325 | 319 | } else if (val == 2) { |
|---|
| 326 | | - fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN | |
|---|
| 327 | | - MAX31790_FAN_CFG_RPM_MODE; |
|---|
| 320 | + fan_config &= ~MAX31790_FAN_CFG_CTRL_MON; |
|---|
| 321 | + /* |
|---|
| 322 | + * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its |
|---|
| 323 | + * own if MAX31790_FAN_CFG_RPM_MODE is set. |
|---|
| 324 | + * Do it here as well to reflect the actual register |
|---|
| 325 | + * value in the cache. |
|---|
| 326 | + */ |
|---|
| 327 | + fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN); |
|---|
| 328 | 328 | } else { |
|---|
| 329 | 329 | err = -EINVAL; |
|---|
| 330 | 330 | break; |
|---|
| 331 | 331 | } |
|---|
| 332 | | - data->fan_config[channel] = fan_config; |
|---|
| 333 | | - err = i2c_smbus_write_byte_data(client, |
|---|
| 334 | | - MAX31790_REG_FAN_CONFIG(channel), |
|---|
| 335 | | - fan_config); |
|---|
| 332 | + if (fan_config != data->fan_config[channel]) { |
|---|
| 333 | + err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel), |
|---|
| 334 | + fan_config); |
|---|
| 335 | + if (!err) |
|---|
| 336 | + data->fan_config[channel] = fan_config; |
|---|
| 337 | + } |
|---|
| 336 | 338 | break; |
|---|
| 337 | 339 | default: |
|---|
| 338 | 340 | err = -EOPNOTSUPP; |
|---|
| .. | .. |
|---|
| 353 | 355 | case hwmon_pwm_input: |
|---|
| 354 | 356 | case hwmon_pwm_enable: |
|---|
| 355 | 357 | if (!(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) |
|---|
| 356 | | - return S_IRUGO | S_IWUSR; |
|---|
| 358 | + return 0644; |
|---|
| 357 | 359 | return 0; |
|---|
| 358 | 360 | default: |
|---|
| 359 | 361 | return 0; |
|---|
| .. | .. |
|---|
| 400 | 402 | } |
|---|
| 401 | 403 | } |
|---|
| 402 | 404 | |
|---|
| 403 | | -static const u32 max31790_fan_config[] = { |
|---|
| 404 | | - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 405 | | - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 406 | | - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 407 | | - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 408 | | - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 409 | | - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 410 | | - HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 411 | | - HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 412 | | - HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 413 | | - HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 414 | | - HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 415 | | - HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 416 | | - 0 |
|---|
| 417 | | -}; |
|---|
| 418 | | - |
|---|
| 419 | | -static const struct hwmon_channel_info max31790_fan = { |
|---|
| 420 | | - .type = hwmon_fan, |
|---|
| 421 | | - .config = max31790_fan_config, |
|---|
| 422 | | -}; |
|---|
| 423 | | - |
|---|
| 424 | | -static const u32 max31790_pwm_config[] = { |
|---|
| 425 | | - HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 426 | | - HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 427 | | - HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 428 | | - HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 429 | | - HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 430 | | - HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 431 | | - 0 |
|---|
| 432 | | -}; |
|---|
| 433 | | - |
|---|
| 434 | | -static const struct hwmon_channel_info max31790_pwm = { |
|---|
| 435 | | - .type = hwmon_pwm, |
|---|
| 436 | | - .config = max31790_pwm_config, |
|---|
| 437 | | -}; |
|---|
| 438 | | - |
|---|
| 439 | 405 | static const struct hwmon_channel_info *max31790_info[] = { |
|---|
| 440 | | - &max31790_fan, |
|---|
| 441 | | - &max31790_pwm, |
|---|
| 406 | + HWMON_CHANNEL_INFO(fan, |
|---|
| 407 | + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 408 | + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 409 | + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 410 | + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 411 | + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 412 | + HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, |
|---|
| 413 | + HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 414 | + HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 415 | + HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 416 | + HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 417 | + HWMON_F_INPUT | HWMON_F_FAULT, |
|---|
| 418 | + HWMON_F_INPUT | HWMON_F_FAULT), |
|---|
| 419 | + HWMON_CHANNEL_INFO(pwm, |
|---|
| 420 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 421 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 422 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 423 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 424 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
|---|
| 425 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), |
|---|
| 442 | 426 | NULL |
|---|
| 443 | 427 | }; |
|---|
| 444 | 428 | |
|---|
| .. | .. |
|---|
| 475 | 459 | return 0; |
|---|
| 476 | 460 | } |
|---|
| 477 | 461 | |
|---|
| 478 | | -static int max31790_probe(struct i2c_client *client, |
|---|
| 479 | | - const struct i2c_device_id *id) |
|---|
| 462 | +static int max31790_probe(struct i2c_client *client) |
|---|
| 480 | 463 | { |
|---|
| 481 | 464 | struct i2c_adapter *adapter = client->adapter; |
|---|
| 482 | 465 | struct device *dev = &client->dev; |
|---|
| .. | .. |
|---|
| 518 | 501 | |
|---|
| 519 | 502 | static struct i2c_driver max31790_driver = { |
|---|
| 520 | 503 | .class = I2C_CLASS_HWMON, |
|---|
| 521 | | - .probe = max31790_probe, |
|---|
| 504 | + .probe_new = max31790_probe, |
|---|
| 522 | 505 | .driver = { |
|---|
| 523 | 506 | .name = "max31790", |
|---|
| 524 | 507 | }, |
|---|