linux/drivers/hwmon/sch5627.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/***************************************************************************
   3 *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *
   4 *                                                                         *
   5 ***************************************************************************/
   6
   7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   8
   9#include <linux/module.h>
  10#include <linux/mod_devicetable.h>
  11#include <linux/init.h>
  12#include <linux/slab.h>
  13#include <linux/jiffies.h>
  14#include <linux/platform_device.h>
  15#include <linux/hwmon.h>
  16#include <linux/err.h>
  17#include <linux/mutex.h>
  18#include "sch56xx-common.h"
  19
  20#define DRVNAME "sch5627"
  21#define DEVNAME DRVNAME /* We only support one model */
  22
  23#define SCH5627_HWMON_ID                0xa5
  24#define SCH5627_COMPANY_ID              0x5c
  25#define SCH5627_PRIMARY_ID              0xa0
  26
  27#define SCH5627_REG_BUILD_CODE          0x39
  28#define SCH5627_REG_BUILD_ID            0x3a
  29#define SCH5627_REG_HWMON_ID            0x3c
  30#define SCH5627_REG_HWMON_REV           0x3d
  31#define SCH5627_REG_COMPANY_ID          0x3e
  32#define SCH5627_REG_PRIMARY_ID          0x3f
  33#define SCH5627_REG_CTRL                0x40
  34
  35#define SCH5627_NO_TEMPS                8
  36#define SCH5627_NO_FANS                 4
  37#define SCH5627_NO_IN                   5
  38
  39static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {
  40        0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };
  41static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {
  42        0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };
  43static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {
  44        0, 0, 1, 1, 0, 0, 0, 1 };
  45static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {
  46        0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };
  47static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {
  48        0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };
  49
  50static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
  51        0x2C, 0x2E, 0x30, 0x32 };
  52static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
  53        0x62, 0x64, 0x66, 0x68 };
  54
  55static const u16 SCH5627_REG_PWM_MAP[SCH5627_NO_FANS] = {
  56        0xA0, 0xA1, 0xA2, 0xA3 };
  57
  58static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
  59        0x22, 0x23, 0x24, 0x25, 0x189 };
  60static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
  61        0xE4, 0xE4, 0xE3, 0xE3, 0x18A };
  62static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {
  63        1, 0, 1, 0, 1 };
  64static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {
  65        10745, 3660, 9765, 10745, 3660 };
  66static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
  67        "VCC", "VTT", "VBAT", "VTR", "V_IN" };
  68
  69struct sch5627_data {
  70        unsigned short addr;
  71        u8 control;
  72        u8 temp_max[SCH5627_NO_TEMPS];
  73        u8 temp_crit[SCH5627_NO_TEMPS];
  74        u16 fan_min[SCH5627_NO_FANS];
  75
  76        struct mutex update_lock;
  77        unsigned long last_battery;     /* In jiffies */
  78        char temp_valid;                /* !=0 if following fields are valid */
  79        char fan_valid;
  80        char in_valid;
  81        unsigned long temp_last_updated;        /* In jiffies */
  82        unsigned long fan_last_updated;
  83        unsigned long in_last_updated;
  84        u16 temp[SCH5627_NO_TEMPS];
  85        u16 fan[SCH5627_NO_FANS];
  86        u16 in[SCH5627_NO_IN];
  87};
  88
  89static int sch5627_update_temp(struct sch5627_data *data)
  90{
  91        int ret = 0;
  92        int i, val;
  93
  94        mutex_lock(&data->update_lock);
  95
  96        /* Cache the values for 1 second */
  97        if (time_after(jiffies, data->temp_last_updated + HZ) || !data->temp_valid) {
  98                for (i = 0; i < SCH5627_NO_TEMPS; i++) {
  99                        val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_TEMP_MSB[i],
 100                                                         SCH5627_REG_TEMP_LSN[i],
 101                                                         SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
 102                        if (unlikely(val < 0)) {
 103                                ret = val;
 104                                goto abort;
 105                        }
 106                        data->temp[i] = val;
 107                }
 108                data->temp_last_updated = jiffies;
 109                data->temp_valid = 1;
 110        }
 111abort:
 112        mutex_unlock(&data->update_lock);
 113        return ret;
 114}
 115
 116static int sch5627_update_fan(struct sch5627_data *data)
 117{
 118        int ret = 0;
 119        int i, val;
 120
 121        mutex_lock(&data->update_lock);
 122
 123        /* Cache the values for 1 second */
 124        if (time_after(jiffies, data->fan_last_updated + HZ) || !data->fan_valid) {
 125                for (i = 0; i < SCH5627_NO_FANS; i++) {
 126                        val = sch56xx_read_virtual_reg16(data->addr, SCH5627_REG_FAN[i]);
 127                        if (unlikely(val < 0)) {
 128                                ret = val;
 129                                goto abort;
 130                        }
 131                        data->fan[i] = val;
 132                }
 133                data->fan_last_updated = jiffies;
 134                data->fan_valid = 1;
 135        }
 136abort:
 137        mutex_unlock(&data->update_lock);
 138        return ret;
 139}
 140
 141static int sch5627_update_in(struct sch5627_data *data)
 142{
 143        int ret = 0;
 144        int i, val;
 145
 146        mutex_lock(&data->update_lock);
 147
 148        /* Trigger a Vbat voltage measurement every 5 minutes */
 149        if (time_after(jiffies, data->last_battery + 300 * HZ)) {
 150                sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | 0x10);
 151                data->last_battery = jiffies;
 152        }
 153
 154        /* Cache the values for 1 second */
 155        if (time_after(jiffies, data->in_last_updated + HZ) || !data->in_valid) {
 156                for (i = 0; i < SCH5627_NO_IN; i++) {
 157                        val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_IN_MSB[i],
 158                                                         SCH5627_REG_IN_LSN[i],
 159                                                         SCH5627_REG_IN_HIGH_NIBBLE[i]);
 160                        if (unlikely(val < 0)) {
 161                                ret = val;
 162                                goto abort;
 163                        }
 164                        data->in[i] = val;
 165                }
 166                data->in_last_updated = jiffies;
 167                data->in_valid = 1;
 168        }
 169abort:
 170        mutex_unlock(&data->update_lock);
 171        return ret;
 172}
 173
 174static int sch5627_read_limits(struct sch5627_data *data)
 175{
 176        int i, val;
 177
 178        for (i = 0; i < SCH5627_NO_TEMPS; i++) {
 179                /*
 180                 * Note what SMSC calls ABS, is what lm_sensors calls max
 181                 * (aka high), and HIGH is what lm_sensors calls crit.
 182                 */
 183                val = sch56xx_read_virtual_reg(data->addr,
 184                                               SCH5627_REG_TEMP_ABS[i]);
 185                if (val < 0)
 186                        return val;
 187                data->temp_max[i] = val;
 188
 189                val = sch56xx_read_virtual_reg(data->addr,
 190                                               SCH5627_REG_TEMP_HIGH[i]);
 191                if (val < 0)
 192                        return val;
 193                data->temp_crit[i] = val;
 194        }
 195        for (i = 0; i < SCH5627_NO_FANS; i++) {
 196                val = sch56xx_read_virtual_reg16(data->addr,
 197                                                 SCH5627_REG_FAN_MIN[i]);
 198                if (val < 0)
 199                        return val;
 200                data->fan_min[i] = val;
 201        }
 202
 203        return 0;
 204}
 205
 206static int reg_to_temp(u16 reg)
 207{
 208        return (reg * 625) / 10 - 64000;
 209}
 210
 211static int reg_to_temp_limit(u8 reg)
 212{
 213        return (reg - 64) * 1000;
 214}
 215
 216static int reg_to_rpm(u16 reg)
 217{
 218        if (reg == 0)
 219                return -EIO;
 220        if (reg == 0xffff)
 221                return 0;
 222
 223        return 5400540 / reg;
 224}
 225
 226static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
 227                                  int channel)
 228{
 229        if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp)
 230                return 0644;
 231
 232        return 0444;
 233}
 234
 235static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
 236                        long *val)
 237{
 238        struct sch5627_data *data = dev_get_drvdata(dev);
 239        int ret;
 240
 241        switch (type) {
 242        case hwmon_temp:
 243                ret = sch5627_update_temp(data);
 244                if (ret < 0)
 245                        return ret;
 246                switch (attr) {
 247                case hwmon_temp_input:
 248                        *val = reg_to_temp(data->temp[channel]);
 249                        return 0;
 250                case hwmon_temp_max:
 251                        *val = reg_to_temp_limit(data->temp_max[channel]);
 252                        return 0;
 253                case hwmon_temp_crit:
 254                        *val = reg_to_temp_limit(data->temp_crit[channel]);
 255                        return 0;
 256                case hwmon_temp_fault:
 257                        *val = (data->temp[channel] == 0);
 258                        return 0;
 259                default:
 260                        break;
 261                }
 262                break;
 263        case hwmon_fan:
 264                ret = sch5627_update_fan(data);
 265                if (ret < 0)
 266                        return ret;
 267                switch (attr) {
 268                case hwmon_fan_input:
 269                        ret = reg_to_rpm(data->fan[channel]);
 270                        if (ret < 0)
 271                                return ret;
 272                        *val = ret;
 273                        return 0;
 274                case hwmon_fan_min:
 275                        ret = reg_to_rpm(data->fan_min[channel]);
 276                        if (ret < 0)
 277                                return ret;
 278                        *val = ret;
 279                        return 0;
 280                case hwmon_fan_fault:
 281                        *val = (data->fan[channel] == 0xffff);
 282                        return 0;
 283                default:
 284                        break;
 285                }
 286                break;
 287        case hwmon_pwm:
 288                switch (attr) {
 289                case hwmon_pwm_auto_channels_temp:
 290                        mutex_lock(&data->update_lock);
 291                        ret = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel]);
 292                        mutex_unlock(&data->update_lock);
 293
 294                        if (ret < 0)
 295                                return ret;
 296
 297                        *val = ret;
 298
 299                        return 0;
 300                default:
 301                        break;
 302                }
 303                break;
 304        case hwmon_in:
 305                ret = sch5627_update_in(data);
 306                if (ret < 0)
 307                        return ret;
 308                switch (attr) {
 309                case hwmon_in_input:
 310                        *val = DIV_ROUND_CLOSEST(data->in[channel] * SCH5627_REG_IN_FACTOR[channel],
 311                                                 10000);
 312                        return 0;
 313                default:
 314                        break;
 315                }
 316                break;
 317        default:
 318                break;
 319        }
 320
 321        return -EOPNOTSUPP;
 322}
 323
 324static int sch5627_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 325                               int channel, const char **str)
 326{
 327        switch (type) {
 328        case hwmon_in:
 329                switch (attr) {
 330                case hwmon_in_label:
 331                        *str = SCH5627_IN_LABELS[channel];
 332                        return 0;
 333                default:
 334                        break;
 335                }
 336                break;
 337        default:
 338                break;
 339        }
 340
 341        return -EOPNOTSUPP;
 342}
 343
 344static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
 345                         long val)
 346{
 347        struct sch5627_data *data = dev_get_drvdata(dev);
 348        int ret;
 349
 350        switch (type) {
 351        case hwmon_pwm:
 352                switch (attr) {
 353                case hwmon_pwm_auto_channels_temp:
 354                        /* registers are 8 bit wide */
 355                        if (val > U8_MAX || val < 0)
 356                                return -EINVAL;
 357
 358                        mutex_lock(&data->update_lock);
 359                        ret = sch56xx_write_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel],
 360                                                        val);
 361                        mutex_unlock(&data->update_lock);
 362
 363                        return ret;
 364                default:
 365                        break;
 366                }
 367                break;
 368        default:
 369                break;
 370        }
 371
 372        return -EOPNOTSUPP;
 373}
 374
 375static const struct hwmon_ops sch5627_ops = {
 376        .is_visible = sch5627_is_visible,
 377        .read = sch5627_read,
 378        .read_string = sch5627_read_string,
 379        .write = sch5627_write,
 380};
 381
 382static const struct hwmon_channel_info *sch5627_info[] = {
 383        HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
 384        HWMON_CHANNEL_INFO(temp,
 385                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 386                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 387                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 388                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 389                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 390                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 391                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
 392                           HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT
 393                           ),
 394        HWMON_CHANNEL_INFO(fan,
 395                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
 396                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
 397                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
 398                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT
 399                           ),
 400        HWMON_CHANNEL_INFO(pwm,
 401                           HWMON_PWM_AUTO_CHANNELS_TEMP,
 402                           HWMON_PWM_AUTO_CHANNELS_TEMP,
 403                           HWMON_PWM_AUTO_CHANNELS_TEMP,
 404                           HWMON_PWM_AUTO_CHANNELS_TEMP
 405                           ),
 406        HWMON_CHANNEL_INFO(in,
 407                           HWMON_I_INPUT | HWMON_I_LABEL,
 408                           HWMON_I_INPUT | HWMON_I_LABEL,
 409                           HWMON_I_INPUT | HWMON_I_LABEL,
 410                           HWMON_I_INPUT | HWMON_I_LABEL,
 411                           HWMON_I_INPUT
 412                           ),
 413        NULL
 414};
 415
 416static const struct hwmon_chip_info sch5627_chip_info = {
 417        .ops = &sch5627_ops,
 418        .info = sch5627_info,
 419};
 420
 421static int sch5627_probe(struct platform_device *pdev)
 422{
 423        struct sch5627_data *data;
 424        struct device *hwmon_dev;
 425        int err, build_code, build_id, hwmon_rev, val;
 426
 427        data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
 428                            GFP_KERNEL);
 429        if (!data)
 430                return -ENOMEM;
 431
 432        data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
 433        mutex_init(&data->update_lock);
 434        platform_set_drvdata(pdev, data);
 435
 436        val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID);
 437        if (val < 0)
 438                return val;
 439
 440        if (val != SCH5627_HWMON_ID) {
 441                pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
 442                       val, SCH5627_HWMON_ID);
 443                return -ENODEV;
 444        }
 445
 446        val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID);
 447        if (val < 0)
 448                return val;
 449
 450        if (val != SCH5627_COMPANY_ID) {
 451                pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
 452                       val, SCH5627_COMPANY_ID);
 453                return -ENODEV;
 454        }
 455
 456        val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID);
 457        if (val < 0)
 458                return val;
 459
 460        if (val != SCH5627_PRIMARY_ID) {
 461                pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
 462                       val, SCH5627_PRIMARY_ID);
 463                return -ENODEV;
 464        }
 465
 466        build_code = sch56xx_read_virtual_reg(data->addr,
 467                                              SCH5627_REG_BUILD_CODE);
 468        if (build_code < 0)
 469                return build_code;
 470
 471        build_id = sch56xx_read_virtual_reg16(data->addr,
 472                                              SCH5627_REG_BUILD_ID);
 473        if (build_id < 0)
 474                return build_id;
 475
 476        hwmon_rev = sch56xx_read_virtual_reg(data->addr,
 477                                             SCH5627_REG_HWMON_REV);
 478        if (hwmon_rev < 0)
 479                return hwmon_rev;
 480
 481        val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL);
 482        if (val < 0)
 483                return val;
 484
 485        data->control = val;
 486        if (!(data->control & 0x01)) {
 487                pr_err("hardware monitoring not enabled\n");
 488                return -ENODEV;
 489        }
 490        /* Trigger a Vbat voltage measurement, so that we get a valid reading
 491           the first time we read Vbat */
 492        sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
 493                                  data->control | 0x10);
 494        data->last_battery = jiffies;
 495
 496        /*
 497         * Read limits, we do this only once as reading a register on
 498         * the sch5627 is quite expensive (and they don't change).
 499         */
 500        err = sch5627_read_limits(data);
 501        if (err)
 502                return err;
 503
 504        pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);
 505        pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
 506                build_code, build_id, hwmon_rev);
 507
 508        hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, DEVNAME, data,
 509                                                         &sch5627_chip_info, NULL);
 510        if (IS_ERR(hwmon_dev))
 511                return PTR_ERR(hwmon_dev);
 512
 513        /* Note failing to register the watchdog is not a fatal error */
 514        sch56xx_watchdog_register(&pdev->dev, data->addr,
 515                                  (build_code << 24) | (build_id << 8) | hwmon_rev,
 516                                  &data->update_lock, 1);
 517
 518        return 0;
 519}
 520
 521static const struct platform_device_id sch5627_device_id[] = {
 522        {
 523                .name = "sch5627",
 524        },
 525        { }
 526};
 527MODULE_DEVICE_TABLE(platform, sch5627_device_id);
 528
 529static struct platform_driver sch5627_driver = {
 530        .driver = {
 531                .name   = DRVNAME,
 532        },
 533        .probe          = sch5627_probe,
 534        .id_table       = sch5627_device_id,
 535};
 536
 537module_platform_driver(sch5627_driver);
 538
 539MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
 540MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 541MODULE_LICENSE("GPL");
 542