linux/drivers/hwmon/mlxreg-fan.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2//
   3// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
   4// Copyright (c) 2018 Vadim Pasternak <vadimp@mellanox.com>
   5
   6#include <linux/bitops.h>
   7#include <linux/device.h>
   8#include <linux/hwmon.h>
   9#include <linux/module.h>
  10#include <linux/platform_data/mlxreg.h>
  11#include <linux/platform_device.h>
  12#include <linux/regmap.h>
  13#include <linux/thermal.h>
  14
  15#define MLXREG_FAN_MAX_TACHO            14
  16#define MLXREG_FAN_MAX_PWM              4
  17#define MLXREG_FAN_PWM_NOT_CONNECTED    0xff
  18#define MLXREG_FAN_MAX_STATE            10
  19#define MLXREG_FAN_MIN_DUTY             51      /* 20% */
  20#define MLXREG_FAN_MAX_DUTY             255     /* 100% */
  21#define MLXREG_FAN_SPEED_MIN_LEVEL              2       /* 20 percent */
  22#define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF  44
  23#define MLXREG_FAN_TACHO_DIV_MIN                283
  24#define MLXREG_FAN_TACHO_DIV_DEF                (MLXREG_FAN_TACHO_DIV_MIN * 4)
  25#define MLXREG_FAN_TACHO_DIV_SCALE_MAX  64
  26/*
  27 * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high.
  28 * The logic in a programmable device measures the time t-high by sampling the
  29 * tachometer every t-sample (with the default value 11.32 uS) and increment
  30 * a counter (N) as long as the pulse has not change:
  31 * RPM = 15 / (t-sample * (K + Regval)), where:
  32 * Regval: is the value read from the programmable device register;
  33 *  - 0xff - represents tachometer fault;
  34 *  - 0xfe - represents tachometer minimum value , which is 4444 RPM;
  35 *  - 0x00 - represents tachometer maximum value , which is 300000 RPM;
  36 * K: is 44 and it represents the minimum allowed samples per pulse;
  37 * N: is equal K + Regval;
  38 * In order to calculate RPM from the register value the following formula is
  39 * used: RPM = 15 / ((Regval + K) * 11.32) * 10^(-6)), which in  the
  40 * default case is modified to:
  41 * RPM = 15000000 * 100 / ((Regval + 44) * 1132);
  42 * - for Regval 0x00, RPM will be 15000000 * 100 / (44 * 1132) = 30115;
  43 * - for Regval 0xfe, RPM will be 15000000 * 100 / ((254 + 44) * 1132) = 4446;
  44 * In common case the formula is modified to:
  45 * RPM = 15000000 * 100 / ((Regval + samples) * divider).
  46 */
  47#define MLXREG_FAN_GET_RPM(rval, d, s)  (DIV_ROUND_CLOSEST(15000000 * 100, \
  48                                         ((rval) + (s)) * (d)))
  49#define MLXREG_FAN_GET_FAULT(val, mask) ((val) == (mask))
  50#define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) *     \
  51                                         MLXREG_FAN_MAX_STATE,          \
  52                                         MLXREG_FAN_MAX_DUTY))
  53#define MLXREG_FAN_PWM_STATE2DUTY(stat) (DIV_ROUND_CLOSEST((stat) *     \
  54                                         MLXREG_FAN_MAX_DUTY,           \
  55                                         MLXREG_FAN_MAX_STATE))
  56
  57struct mlxreg_fan;
  58
  59/*
  60 * struct mlxreg_fan_tacho - tachometer data (internal use):
  61 *
  62 * @connected: indicates if tachometer is connected;
  63 * @reg: register offset;
  64 * @mask: fault mask;
  65 * @prsnt: present register offset;
  66 */
  67struct mlxreg_fan_tacho {
  68        bool connected;
  69        u32 reg;
  70        u32 mask;
  71        u32 prsnt;
  72};
  73
  74/*
  75 * struct mlxreg_fan_pwm - PWM data (internal use):
  76 *
  77 * @fan: private data;
  78 * @connected: indicates if PWM is connected;
  79 * @reg: register offset;
  80 * @cooling: cooling device levels;
  81 * @last_hwmon_state: last cooling state set by hwmon subsystem;
  82 * @last_thermal_state: last cooling state set by thermal subsystem;
  83 * @cdev: cooling device;
  84 */
  85struct mlxreg_fan_pwm {
  86        struct mlxreg_fan *fan;
  87        bool connected;
  88        u32 reg;
  89        unsigned long last_hwmon_state;
  90        unsigned long last_thermal_state;
  91        struct thermal_cooling_device *cdev;
  92};
  93
  94/*
  95 * struct mlxreg_fan - private data (internal use):
  96 *
  97 * @dev: basic device;
  98 * @regmap: register map of parent device;
  99 * @tacho: tachometer data;
 100 * @pwm: PWM data;
 101 * @tachos_per_drwr - number of tachometers per drawer;
 102 * @samples: minimum allowed samples per pulse;
 103 * @divider: divider value for tachometer RPM calculation;
 104 */
 105struct mlxreg_fan {
 106        struct device *dev;
 107        void *regmap;
 108        struct mlxreg_core_platform_data *pdata;
 109        struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO];
 110        struct mlxreg_fan_pwm pwm[MLXREG_FAN_MAX_PWM];
 111        int tachos_per_drwr;
 112        int samples;
 113        int divider;
 114};
 115
 116static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
 117                                    unsigned long state);
 118
 119static int
 120mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 121                int channel, long *val)
 122{
 123        struct mlxreg_fan *fan = dev_get_drvdata(dev);
 124        struct mlxreg_fan_tacho *tacho;
 125        struct mlxreg_fan_pwm *pwm;
 126        u32 regval;
 127        int err;
 128
 129        switch (type) {
 130        case hwmon_fan:
 131                tacho = &fan->tacho[channel];
 132                switch (attr) {
 133                case hwmon_fan_input:
 134                        /*
 135                         * Check FAN presence: FAN related bit in presence register is one,
 136                         * if FAN is physically connected, zero - otherwise.
 137                         */
 138                        if (tacho->prsnt && fan->tachos_per_drwr) {
 139                                err = regmap_read(fan->regmap, tacho->prsnt, &regval);
 140                                if (err)
 141                                        return err;
 142
 143                                /*
 144                                 * Map channel to presence bit - drawer can be equipped with
 145                                 * one or few FANs, while presence is indicated per drawer.
 146                                 */
 147                                if (BIT(channel / fan->tachos_per_drwr) & regval) {
 148                                        /* FAN is not connected - return zero for FAN speed. */
 149                                        *val = 0;
 150                                        return 0;
 151                                }
 152                        }
 153
 154                        err = regmap_read(fan->regmap, tacho->reg, &regval);
 155                        if (err)
 156                                return err;
 157
 158                        *val = MLXREG_FAN_GET_RPM(regval, fan->divider,
 159                                                  fan->samples);
 160                        break;
 161
 162                case hwmon_fan_fault:
 163                        err = regmap_read(fan->regmap, tacho->reg, &regval);
 164                        if (err)
 165                                return err;
 166
 167                        *val = MLXREG_FAN_GET_FAULT(regval, tacho->mask);
 168                        break;
 169
 170                default:
 171                        return -EOPNOTSUPP;
 172                }
 173                break;
 174
 175        case hwmon_pwm:
 176                pwm = &fan->pwm[channel];
 177                switch (attr) {
 178                case hwmon_pwm_input:
 179                        err = regmap_read(fan->regmap, pwm->reg, &regval);
 180                        if (err)
 181                                return err;
 182
 183                        *val = regval;
 184                        break;
 185
 186                default:
 187                        return -EOPNOTSUPP;
 188                }
 189                break;
 190
 191        default:
 192                return -EOPNOTSUPP;
 193        }
 194
 195        return 0;
 196}
 197
 198static int
 199mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 200                 int channel, long val)
 201{
 202        struct mlxreg_fan *fan = dev_get_drvdata(dev);
 203        struct mlxreg_fan_pwm *pwm;
 204
 205        switch (type) {
 206        case hwmon_pwm:
 207                switch (attr) {
 208                case hwmon_pwm_input:
 209                        if (val < MLXREG_FAN_MIN_DUTY ||
 210                            val > MLXREG_FAN_MAX_DUTY)
 211                                return -EINVAL;
 212                        pwm = &fan->pwm[channel];
 213                        /* If thermal is configured - handle PWM limit setting. */
 214                        if (IS_REACHABLE(CONFIG_THERMAL)) {
 215                                pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(val);
 216                                /*
 217                                 * Update PWM only in case requested state is not less than the
 218                                 * last thermal state.
 219                                 */
 220                                if (pwm->last_hwmon_state >= pwm->last_thermal_state)
 221                                        return mlxreg_fan_set_cur_state(pwm->cdev,
 222                                                                        pwm->last_hwmon_state);
 223                                return 0;
 224                        }
 225                        return regmap_write(fan->regmap, pwm->reg, val);
 226                default:
 227                        return -EOPNOTSUPP;
 228                }
 229                break;
 230
 231        default:
 232                return -EOPNOTSUPP;
 233        }
 234
 235        return -EOPNOTSUPP;
 236}
 237
 238static umode_t
 239mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
 240                      int channel)
 241{
 242        switch (type) {
 243        case hwmon_fan:
 244                if (!(((struct mlxreg_fan *)data)->tacho[channel].connected))
 245                        return 0;
 246
 247                switch (attr) {
 248                case hwmon_fan_input:
 249                case hwmon_fan_fault:
 250                        return 0444;
 251                default:
 252                        break;
 253                }
 254                break;
 255
 256        case hwmon_pwm:
 257                if (!(((struct mlxreg_fan *)data)->pwm[channel].connected))
 258                        return 0;
 259
 260                switch (attr) {
 261                case hwmon_pwm_input:
 262                        return 0644;
 263                default:
 264                        break;
 265                }
 266                break;
 267
 268        default:
 269                break;
 270        }
 271
 272        return 0;
 273}
 274
 275static char *mlxreg_fan_name[] = {
 276        "mlxreg_fan",
 277        "mlxreg_fan1",
 278        "mlxreg_fan2",
 279        "mlxreg_fan3",
 280};
 281
 282static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = {
 283        HWMON_CHANNEL_INFO(fan,
 284                           HWMON_F_INPUT | HWMON_F_FAULT,
 285                           HWMON_F_INPUT | HWMON_F_FAULT,
 286                           HWMON_F_INPUT | HWMON_F_FAULT,
 287                           HWMON_F_INPUT | HWMON_F_FAULT,
 288                           HWMON_F_INPUT | HWMON_F_FAULT,
 289                           HWMON_F_INPUT | HWMON_F_FAULT,
 290                           HWMON_F_INPUT | HWMON_F_FAULT,
 291                           HWMON_F_INPUT | HWMON_F_FAULT,
 292                           HWMON_F_INPUT | HWMON_F_FAULT,
 293                           HWMON_F_INPUT | HWMON_F_FAULT,
 294                           HWMON_F_INPUT | HWMON_F_FAULT,
 295                           HWMON_F_INPUT | HWMON_F_FAULT,
 296                           HWMON_F_INPUT | HWMON_F_FAULT,
 297                           HWMON_F_INPUT | HWMON_F_FAULT),
 298        HWMON_CHANNEL_INFO(pwm,
 299                           HWMON_PWM_INPUT,
 300                           HWMON_PWM_INPUT,
 301                           HWMON_PWM_INPUT,
 302                           HWMON_PWM_INPUT),
 303        NULL
 304};
 305
 306static const struct hwmon_ops mlxreg_fan_hwmon_hwmon_ops = {
 307        .is_visible = mlxreg_fan_is_visible,
 308        .read = mlxreg_fan_read,
 309        .write = mlxreg_fan_write,
 310};
 311
 312static const struct hwmon_chip_info mlxreg_fan_hwmon_chip_info = {
 313        .ops = &mlxreg_fan_hwmon_hwmon_ops,
 314        .info = mlxreg_fan_hwmon_info,
 315};
 316
 317static int mlxreg_fan_get_max_state(struct thermal_cooling_device *cdev,
 318                                    unsigned long *state)
 319{
 320        *state = MLXREG_FAN_MAX_STATE;
 321        return 0;
 322}
 323
 324static int mlxreg_fan_get_cur_state(struct thermal_cooling_device *cdev,
 325                                    unsigned long *state)
 326
 327{
 328        struct mlxreg_fan_pwm *pwm = cdev->devdata;
 329        struct mlxreg_fan *fan = pwm->fan;
 330        u32 regval;
 331        int err;
 332
 333        err = regmap_read(fan->regmap, pwm->reg, &regval);
 334        if (err) {
 335                dev_err(fan->dev, "Failed to query PWM duty\n");
 336                return err;
 337        }
 338
 339        *state = MLXREG_FAN_PWM_DUTY2STATE(regval);
 340
 341        return 0;
 342}
 343
 344static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
 345                                    unsigned long state)
 346
 347{
 348        struct mlxreg_fan_pwm *pwm = cdev->devdata;
 349        struct mlxreg_fan *fan = pwm->fan;
 350        int err;
 351
 352        if (state > MLXREG_FAN_MAX_STATE)
 353                return -EINVAL;
 354
 355        /* Save thermal state. */
 356        pwm->last_thermal_state = state;
 357
 358        state = max_t(unsigned long, state, pwm->last_hwmon_state);
 359        err = regmap_write(fan->regmap, pwm->reg,
 360                           MLXREG_FAN_PWM_STATE2DUTY(state));
 361        if (err) {
 362                dev_err(fan->dev, "Failed to write PWM duty\n");
 363                return err;
 364        }
 365        return 0;
 366}
 367
 368static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = {
 369        .get_max_state  = mlxreg_fan_get_max_state,
 370        .get_cur_state  = mlxreg_fan_get_cur_state,
 371        .set_cur_state  = mlxreg_fan_set_cur_state,
 372};
 373
 374static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan,
 375                                     struct mlxreg_core_data *data)
 376{
 377        u32 regval;
 378        int err;
 379
 380        err = regmap_read(fan->regmap, data->capability, &regval);
 381        if (err) {
 382                dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
 383                        data->capability);
 384                return err;
 385        }
 386
 387        return !!(regval & data->bit);
 388}
 389
 390static int mlxreg_pwm_connect_verify(struct mlxreg_fan *fan,
 391                                     struct mlxreg_core_data *data)
 392{
 393        u32 regval;
 394        int err;
 395
 396        err = regmap_read(fan->regmap, data->reg, &regval);
 397        if (err) {
 398                dev_err(fan->dev, "Failed to query pwm register 0x%08x\n",
 399                        data->reg);
 400                return err;
 401        }
 402
 403        return regval != MLXREG_FAN_PWM_NOT_CONNECTED;
 404}
 405
 406static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan,
 407                                        struct mlxreg_core_data *data)
 408{
 409        u32 regval;
 410        int err;
 411
 412        err = regmap_read(fan->regmap, data->capability, &regval);
 413        if (err) {
 414                dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
 415                        data->capability);
 416                return err;
 417        }
 418
 419        /*
 420         * Set divider value according to the capability register, in case it
 421         * contains valid value. Otherwise use default value. The purpose of
 422         * this validation is to protect against the old hardware, in which
 423         * this register can return zero.
 424         */
 425        if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX)
 426                fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN;
 427
 428        return 0;
 429}
 430
 431static int mlxreg_fan_config(struct mlxreg_fan *fan,
 432                             struct mlxreg_core_platform_data *pdata)
 433{
 434        int tacho_num = 0, tacho_avail = 0, pwm_num = 0, i;
 435        struct mlxreg_core_data *data = pdata->data;
 436        bool configured = false;
 437        int err;
 438
 439        fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF;
 440        fan->divider = MLXREG_FAN_TACHO_DIV_DEF;
 441        for (i = 0; i < pdata->counter; i++, data++) {
 442                if (strnstr(data->label, "tacho", sizeof(data->label))) {
 443                        if (tacho_num == MLXREG_FAN_MAX_TACHO) {
 444                                dev_err(fan->dev, "too many tacho entries: %s\n",
 445                                        data->label);
 446                                return -EINVAL;
 447                        }
 448
 449                        if (data->capability) {
 450                                err = mlxreg_fan_connect_verify(fan, data);
 451                                if (err < 0)
 452                                        return err;
 453                                else if (!err) {
 454                                        tacho_num++;
 455                                        continue;
 456                                }
 457                        }
 458
 459                        fan->tacho[tacho_num].reg = data->reg;
 460                        fan->tacho[tacho_num].mask = data->mask;
 461                        fan->tacho[tacho_num].prsnt = data->reg_prsnt;
 462                        fan->tacho[tacho_num++].connected = true;
 463                        tacho_avail++;
 464                } else if (strnstr(data->label, "pwm", sizeof(data->label))) {
 465                        if (pwm_num == MLXREG_FAN_MAX_TACHO) {
 466                                dev_err(fan->dev, "too many pwm entries: %s\n",
 467                                        data->label);
 468                                return -EINVAL;
 469                        }
 470
 471                        /* Validate if more then one PWM is connected. */
 472                        if (pwm_num) {
 473                                err = mlxreg_pwm_connect_verify(fan, data);
 474                                if (err < 0)
 475                                        return err;
 476                                else if (!err)
 477                                        continue;
 478                        }
 479
 480                        fan->pwm[pwm_num].reg = data->reg;
 481                        fan->pwm[pwm_num].connected = true;
 482                        pwm_num++;
 483                } else if (strnstr(data->label, "conf", sizeof(data->label))) {
 484                        if (configured) {
 485                                dev_err(fan->dev, "duplicate conf entry: %s\n",
 486                                        data->label);
 487                                return -EINVAL;
 488                        }
 489                        /* Validate that conf parameters are not zeros. */
 490                        if (!data->mask && !data->bit && !data->capability) {
 491                                dev_err(fan->dev, "invalid conf entry params: %s\n",
 492                                        data->label);
 493                                return -EINVAL;
 494                        }
 495                        if (data->capability) {
 496                                err = mlxreg_fan_speed_divider_get(fan, data);
 497                                if (err)
 498                                        return err;
 499                        } else {
 500                                if (data->mask)
 501                                        fan->samples = data->mask;
 502                                if (data->bit)
 503                                        fan->divider = data->bit;
 504                        }
 505                        configured = true;
 506                } else {
 507                        dev_err(fan->dev, "invalid label: %s\n", data->label);
 508                        return -EINVAL;
 509                }
 510        }
 511
 512        if (pdata->capability) {
 513                int drwr_avail;
 514                u32 regval;
 515
 516                /* Obtain the number of FAN drawers, supported by system. */
 517                err = regmap_read(fan->regmap, pdata->capability, &regval);
 518                if (err) {
 519                        dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
 520                                pdata->capability);
 521                        return err;
 522                }
 523
 524                drwr_avail = hweight32(regval);
 525                if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) {
 526                        dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n",
 527                                drwr_avail, tacho_avail);
 528                        return -EINVAL;
 529                }
 530
 531                /* Set the number of tachometers per one drawer. */
 532                fan->tachos_per_drwr = tacho_avail / drwr_avail;
 533        }
 534
 535        return 0;
 536}
 537
 538static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
 539{
 540        int i;
 541
 542        for (i = 0; i < MLXREG_FAN_MAX_PWM; i++) {
 543                struct mlxreg_fan_pwm *pwm = &fan->pwm[i];
 544
 545                if (!pwm->connected)
 546                        continue;
 547                pwm->fan = fan;
 548                pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i],
 549                                                                    pwm, &mlxreg_fan_cooling_ops);
 550                if (IS_ERR(pwm->cdev)) {
 551                        dev_err(dev, "Failed to register cooling device\n");
 552                        return PTR_ERR(pwm->cdev);
 553                }
 554
 555                /* Set minimal PWM speed. */
 556                pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY);
 557        }
 558
 559        return 0;
 560}
 561
 562static int mlxreg_fan_probe(struct platform_device *pdev)
 563{
 564        struct mlxreg_core_platform_data *pdata;
 565        struct device *dev = &pdev->dev;
 566        struct mlxreg_fan *fan;
 567        struct device *hwm;
 568        int err;
 569
 570        pdata = dev_get_platdata(dev);
 571        if (!pdata) {
 572                dev_err(dev, "Failed to get platform data.\n");
 573                return -EINVAL;
 574        }
 575
 576        fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL);
 577        if (!fan)
 578                return -ENOMEM;
 579
 580        fan->dev = dev;
 581        fan->regmap = pdata->regmap;
 582
 583        err = mlxreg_fan_config(fan, pdata);
 584        if (err)
 585                return err;
 586
 587        hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan",
 588                                                   fan,
 589                                                   &mlxreg_fan_hwmon_chip_info,
 590                                                   NULL);
 591        if (IS_ERR(hwm)) {
 592                dev_err(dev, "Failed to register hwmon device\n");
 593                return PTR_ERR(hwm);
 594        }
 595
 596        if (IS_REACHABLE(CONFIG_THERMAL))
 597                err = mlxreg_fan_cooling_config(dev, fan);
 598
 599        return err;
 600}
 601
 602static struct platform_driver mlxreg_fan_driver = {
 603        .driver = {
 604            .name = "mlxreg-fan",
 605        },
 606        .probe = mlxreg_fan_probe,
 607};
 608
 609module_platform_driver(mlxreg_fan_driver);
 610
 611MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
 612MODULE_DESCRIPTION("Mellanox FAN driver");
 613MODULE_LICENSE("GPL");
 614MODULE_ALIAS("platform:mlxreg-fan");
 615