linux/drivers/hwmon/nct7904.c
<<
>>
Prefs
   1/*
   2 * nct7904.c - driver for Nuvoton NCT7904D.
   3 *
   4 * Copyright (c) 2015 Kontron
   5 * Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>
   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 */
  17
  18#include <linux/module.h>
  19#include <linux/device.h>
  20#include <linux/init.h>
  21#include <linux/i2c.h>
  22#include <linux/mutex.h>
  23#include <linux/hwmon.h>
  24
  25#define VENDOR_ID_REG           0x7A    /* Any bank */
  26#define NUVOTON_ID              0x50
  27#define CHIP_ID_REG             0x7B    /* Any bank */
  28#define NCT7904_ID              0xC5
  29#define DEVICE_ID_REG           0x7C    /* Any bank */
  30
  31#define BANK_SEL_REG            0xFF
  32#define BANK_0                  0x00
  33#define BANK_1                  0x01
  34#define BANK_2                  0x02
  35#define BANK_3                  0x03
  36#define BANK_4                  0x04
  37#define BANK_MAX                0x04
  38
  39#define FANIN_MAX               12      /* Counted from 1 */
  40#define VSEN_MAX                21      /* VSEN1..14, 3VDD, VBAT, V3VSB,
  41                                           LTD (not a voltage), VSEN17..19 */
  42#define FANCTL_MAX              4       /* Counted from 1 */
  43#define TCPU_MAX                8       /* Counted from 1 */
  44#define TEMP_MAX                4       /* Counted from 1 */
  45
  46#define VT_ADC_CTRL0_REG        0x20    /* Bank 0 */
  47#define VT_ADC_CTRL1_REG        0x21    /* Bank 0 */
  48#define VT_ADC_CTRL2_REG        0x22    /* Bank 0 */
  49#define FANIN_CTRL0_REG         0x24
  50#define FANIN_CTRL1_REG         0x25
  51#define DTS_T_CTRL0_REG         0x26
  52#define DTS_T_CTRL1_REG         0x27
  53#define VT_ADC_MD_REG           0x2E
  54
  55#define VSEN1_HV_REG            0x40    /* Bank 0; 2 regs (HV/LV) per sensor */
  56#define TEMP_CH1_HV_REG         0x42    /* Bank 0; same as VSEN2_HV */
  57#define LTD_HV_REG              0x62    /* Bank 0; 2 regs in VSEN range */
  58#define FANIN1_HV_REG           0x80    /* Bank 0; 2 regs (HV/LV) per sensor */
  59#define T_CPU1_HV_REG           0xA0    /* Bank 0; 2 regs (HV/LV) per sensor */
  60
  61#define PRTS_REG                0x03    /* Bank 2 */
  62#define FANCTL1_FMR_REG         0x00    /* Bank 3; 1 reg per channel */
  63#define FANCTL1_OUT_REG         0x10    /* Bank 3; 1 reg per channel */
  64
  65static const unsigned short normal_i2c[] = {
  66        0x2d, 0x2e, I2C_CLIENT_END
  67};
  68
  69struct nct7904_data {
  70        struct i2c_client *client;
  71        struct mutex bank_lock;
  72        int bank_sel;
  73        u32 fanin_mask;
  74        u32 vsen_mask;
  75        u32 tcpu_mask;
  76        u8 fan_mode[FANCTL_MAX];
  77};
  78
  79/* Access functions */
  80static int nct7904_bank_lock(struct nct7904_data *data, unsigned bank)
  81{
  82        int ret;
  83
  84        mutex_lock(&data->bank_lock);
  85        if (data->bank_sel == bank)
  86                return 0;
  87        ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank);
  88        if (ret == 0)
  89                data->bank_sel = bank;
  90        else
  91                data->bank_sel = -1;
  92        return ret;
  93}
  94
  95static inline void nct7904_bank_release(struct nct7904_data *data)
  96{
  97        mutex_unlock(&data->bank_lock);
  98}
  99
 100/* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */
 101static int nct7904_read_reg(struct nct7904_data *data,
 102                            unsigned bank, unsigned reg)
 103{
 104        struct i2c_client *client = data->client;
 105        int ret;
 106
 107        ret = nct7904_bank_lock(data, bank);
 108        if (ret == 0)
 109                ret = i2c_smbus_read_byte_data(client, reg);
 110
 111        nct7904_bank_release(data);
 112        return ret;
 113}
 114
 115/*
 116 * Read 2-byte register. Returns register in big-endian format or
 117 * -ERRNO on error.
 118 */
 119static int nct7904_read_reg16(struct nct7904_data *data,
 120                              unsigned bank, unsigned reg)
 121{
 122        struct i2c_client *client = data->client;
 123        int ret, hi;
 124
 125        ret = nct7904_bank_lock(data, bank);
 126        if (ret == 0) {
 127                ret = i2c_smbus_read_byte_data(client, reg);
 128                if (ret >= 0) {
 129                        hi = ret;
 130                        ret = i2c_smbus_read_byte_data(client, reg + 1);
 131                        if (ret >= 0)
 132                                ret |= hi << 8;
 133                }
 134        }
 135
 136        nct7904_bank_release(data);
 137        return ret;
 138}
 139
 140/* Write 1-byte register. Returns 0 or -ERRNO on error. */
 141static int nct7904_write_reg(struct nct7904_data *data,
 142                             unsigned bank, unsigned reg, u8 val)
 143{
 144        struct i2c_client *client = data->client;
 145        int ret;
 146
 147        ret = nct7904_bank_lock(data, bank);
 148        if (ret == 0)
 149                ret = i2c_smbus_write_byte_data(client, reg, val);
 150
 151        nct7904_bank_release(data);
 152        return ret;
 153}
 154
 155static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
 156                            long *val)
 157{
 158        struct nct7904_data *data = dev_get_drvdata(dev);
 159        unsigned int cnt, rpm;
 160        int ret;
 161
 162        switch(attr) {
 163        case hwmon_fan_input:
 164                ret = nct7904_read_reg16(data, BANK_0,
 165                                         FANIN1_HV_REG + channel * 2);
 166                if (ret < 0)
 167                        return ret;
 168                cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
 169                if (cnt == 0x1fff)
 170                        rpm = 0;
 171                else
 172                        rpm = 1350000 / cnt;
 173                *val = rpm;
 174                return 0;
 175        default:
 176                return -EOPNOTSUPP;
 177        }
 178}
 179
 180static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel)
 181{
 182        const struct nct7904_data *data = _data;
 183
 184        if (attr == hwmon_fan_input && data->fanin_mask & (1 << channel))
 185                return S_IRUGO;
 186        return 0;
 187}
 188
 189static u8 nct7904_chan_to_index[] = {
 190        0,      /* Not used */
 191        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
 192        18, 19, 20, 16
 193};
 194
 195static int nct7904_read_in(struct device *dev, u32 attr, int channel,
 196                           long *val)
 197{
 198        struct nct7904_data *data = dev_get_drvdata(dev);
 199        int ret, volt, index;
 200
 201        index = nct7904_chan_to_index[channel];
 202
 203        switch(attr) {
 204        case hwmon_in_input:
 205                ret = nct7904_read_reg16(data, BANK_0,
 206                                         VSEN1_HV_REG + index * 2);
 207                if (ret < 0)
 208                        return ret;
 209                volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
 210                if (index < 14)
 211                        volt *= 2; /* 0.002V scale */
 212                else
 213                        volt *= 6; /* 0.006V scale */
 214                *val = volt;
 215                return 0;
 216        default:
 217                return -EOPNOTSUPP;
 218        }
 219}
 220
 221static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel)
 222{
 223        const struct nct7904_data *data = _data;
 224        int index = nct7904_chan_to_index[channel];
 225
 226        if (channel > 0 && attr == hwmon_in_input &&
 227            (data->vsen_mask & BIT(index)))
 228                return S_IRUGO;
 229
 230        return 0;
 231}
 232
 233static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
 234                             long *val)
 235{
 236        struct nct7904_data *data = dev_get_drvdata(dev);
 237        int ret, temp;
 238
 239        switch(attr) {
 240        case hwmon_temp_input:
 241                if (channel == 0)
 242                        ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG);
 243                else
 244                        ret = nct7904_read_reg16(data, BANK_0,
 245                                        T_CPU1_HV_REG + (channel - 1) * 2);
 246                if (ret < 0)
 247                        return ret;
 248                temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
 249                *val = sign_extend32(temp, 10) * 125;
 250                return 0;
 251        default:
 252                return -EOPNOTSUPP;
 253        }
 254}
 255
 256static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
 257{
 258        const struct nct7904_data *data = _data;
 259
 260        if (attr == hwmon_temp_input) {
 261                if (channel == 0) {
 262                        if (data->vsen_mask & BIT(17))
 263                                return S_IRUGO;
 264                } else {
 265                        if (data->tcpu_mask & BIT(channel - 1))
 266                                return S_IRUGO;
 267                }
 268        }
 269
 270        return 0;
 271}
 272
 273static int nct7904_read_pwm(struct device *dev, u32 attr, int channel,
 274                            long *val)
 275{
 276        struct nct7904_data *data = dev_get_drvdata(dev);
 277        int ret;
 278
 279        switch(attr) {
 280        case hwmon_pwm_input:
 281                ret = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + channel);
 282                if (ret < 0)
 283                        return ret;
 284                *val = ret;
 285                return 0;
 286        case hwmon_pwm_enable:
 287                ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + channel);
 288                if (ret < 0)
 289                        return ret;
 290
 291                *val = ret ? 2 : 1;
 292                return 0;
 293        default:
 294                return -EOPNOTSUPP;
 295        }
 296}
 297
 298static int nct7904_write_pwm(struct device *dev, u32 attr, int channel,
 299                             long val)
 300{
 301        struct nct7904_data *data = dev_get_drvdata(dev);
 302        int ret;
 303
 304        switch(attr) {
 305        case hwmon_pwm_input:
 306                if (val < 0 || val > 255)
 307                        return -EINVAL;
 308                ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + channel,
 309                                        val);
 310                return ret;
 311        case hwmon_pwm_enable:
 312                if (val < 1 || val > 2 ||
 313                    (val == 2 && !data->fan_mode[channel]))
 314                        return -EINVAL;
 315                ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + channel,
 316                                        val == 2 ? data->fan_mode[channel] : 0);
 317                return ret;
 318        default:
 319                return -EOPNOTSUPP;
 320        }
 321}
 322
 323static umode_t nct7904_pwm_is_visible(const void *_data, u32 attr, int channel)
 324{
 325        switch(attr) {
 326        case hwmon_pwm_input:
 327        case hwmon_pwm_enable:
 328                return S_IRUGO | S_IWUSR;
 329        default:
 330                return 0;
 331        }
 332}
 333
 334static int nct7904_read(struct device *dev, enum hwmon_sensor_types type,
 335                        u32 attr, int channel, long *val)
 336{
 337        switch (type) {
 338        case hwmon_in:
 339                return nct7904_read_in(dev, attr, channel, val);
 340        case hwmon_fan:
 341                return nct7904_read_fan(dev, attr, channel, val);
 342        case hwmon_pwm:
 343                return nct7904_read_pwm(dev, attr, channel, val);
 344        case hwmon_temp:
 345                return nct7904_read_temp(dev, attr, channel, val);
 346        default:
 347                return -EOPNOTSUPP;
 348        }
 349}
 350
 351static int nct7904_write(struct device *dev, enum hwmon_sensor_types type,
 352                         u32 attr, int channel, long val)
 353{
 354        switch (type) {
 355        case hwmon_pwm:
 356                return nct7904_write_pwm(dev, attr, channel, val);
 357        default:
 358                return -EOPNOTSUPP;
 359        }
 360}
 361
 362static umode_t nct7904_is_visible(const void *data,
 363                                  enum hwmon_sensor_types type,
 364                                  u32 attr, int channel)
 365{
 366        switch (type) {
 367        case hwmon_in:
 368                return nct7904_in_is_visible(data, attr, channel);
 369        case hwmon_fan:
 370                return nct7904_fan_is_visible(data, attr, channel);
 371        case hwmon_pwm:
 372                return nct7904_pwm_is_visible(data, attr, channel);
 373        case hwmon_temp:
 374                return nct7904_temp_is_visible(data, attr, channel);
 375        default:
 376                return 0;
 377        }
 378}
 379
 380/* Return 0 if detection is successful, -ENODEV otherwise */
 381static int nct7904_detect(struct i2c_client *client,
 382                          struct i2c_board_info *info)
 383{
 384        struct i2c_adapter *adapter = client->adapter;
 385
 386        if (!i2c_check_functionality(adapter,
 387                                     I2C_FUNC_SMBUS_READ_BYTE |
 388                                     I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 389                return -ENODEV;
 390
 391        /* Determine the chip type. */
 392        if (i2c_smbus_read_byte_data(client, VENDOR_ID_REG) != NUVOTON_ID ||
 393            i2c_smbus_read_byte_data(client, CHIP_ID_REG) != NCT7904_ID ||
 394            (i2c_smbus_read_byte_data(client, DEVICE_ID_REG) & 0xf0) != 0x50 ||
 395            (i2c_smbus_read_byte_data(client, BANK_SEL_REG) & 0xf8) != 0x00)
 396                return -ENODEV;
 397
 398        strlcpy(info->type, "nct7904", I2C_NAME_SIZE);
 399
 400        return 0;
 401}
 402
 403static const u32 nct7904_in_config[] = {
 404        HWMON_I_INPUT,                  /* dummy, skipped in is_visible */
 405        HWMON_I_INPUT,
 406        HWMON_I_INPUT,
 407        HWMON_I_INPUT,
 408        HWMON_I_INPUT,
 409        HWMON_I_INPUT,
 410        HWMON_I_INPUT,
 411        HWMON_I_INPUT,
 412        HWMON_I_INPUT,
 413        HWMON_I_INPUT,
 414        HWMON_I_INPUT,
 415        HWMON_I_INPUT,
 416        HWMON_I_INPUT,
 417        HWMON_I_INPUT,
 418        HWMON_I_INPUT,
 419        HWMON_I_INPUT,
 420        HWMON_I_INPUT,
 421        HWMON_I_INPUT,
 422        HWMON_I_INPUT,
 423        HWMON_I_INPUT,
 424        HWMON_I_INPUT,
 425        0
 426};
 427
 428static const struct hwmon_channel_info nct7904_in = {
 429        .type = hwmon_in,
 430        .config = nct7904_in_config,
 431};
 432
 433static const u32 nct7904_fan_config[] = {
 434            HWMON_F_INPUT,
 435            HWMON_F_INPUT,
 436            HWMON_F_INPUT,
 437            HWMON_F_INPUT,
 438            HWMON_F_INPUT,
 439            HWMON_F_INPUT,
 440            HWMON_F_INPUT,
 441            HWMON_F_INPUT,
 442            0
 443};
 444
 445static const struct hwmon_channel_info nct7904_fan = {
 446        .type = hwmon_fan,
 447        .config = nct7904_fan_config,
 448};
 449
 450static const u32 nct7904_pwm_config[] = {
 451            HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
 452            HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
 453            HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
 454            HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
 455            0
 456};
 457
 458static const struct hwmon_channel_info nct7904_pwm = {
 459        .type = hwmon_pwm,
 460        .config = nct7904_pwm_config,
 461};
 462
 463static const u32 nct7904_temp_config[] = {
 464            HWMON_T_INPUT,
 465            HWMON_T_INPUT,
 466            HWMON_T_INPUT,
 467            HWMON_T_INPUT,
 468            HWMON_T_INPUT,
 469            HWMON_T_INPUT,
 470            HWMON_T_INPUT,
 471            HWMON_T_INPUT,
 472            HWMON_T_INPUT,
 473            0
 474};
 475
 476static const struct hwmon_channel_info nct7904_temp = {
 477        .type = hwmon_temp,
 478        .config = nct7904_temp_config,
 479};
 480
 481static const struct hwmon_channel_info *nct7904_info[] = {
 482        &nct7904_in,
 483        &nct7904_fan,
 484        &nct7904_pwm,
 485        &nct7904_temp,
 486        NULL
 487};
 488
 489static const struct hwmon_ops nct7904_hwmon_ops = {
 490        .is_visible = nct7904_is_visible,
 491        .read = nct7904_read,
 492        .write = nct7904_write,
 493};
 494
 495static const struct hwmon_chip_info nct7904_chip_info = {
 496        .ops = &nct7904_hwmon_ops,
 497        .info = nct7904_info,
 498};
 499
 500static int nct7904_probe(struct i2c_client *client,
 501                         const struct i2c_device_id *id)
 502{
 503        struct nct7904_data *data;
 504        struct device *hwmon_dev;
 505        struct device *dev = &client->dev;
 506        int ret, i;
 507        u32 mask;
 508
 509        data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL);
 510        if (!data)
 511                return -ENOMEM;
 512
 513        data->client = client;
 514        mutex_init(&data->bank_lock);
 515        data->bank_sel = -1;
 516
 517        /* Setup sensor groups. */
 518        /* FANIN attributes */
 519        ret = nct7904_read_reg16(data, BANK_0, FANIN_CTRL0_REG);
 520        if (ret < 0)
 521                return ret;
 522        data->fanin_mask = (ret >> 8) | ((ret & 0xff) << 8);
 523
 524        /*
 525         * VSEN attributes
 526         *
 527         * Note: voltage sensors overlap with external temperature
 528         * sensors. So, if we ever decide to support the latter
 529         * we will have to adjust 'vsen_mask' accordingly.
 530         */
 531        mask = 0;
 532        ret = nct7904_read_reg16(data, BANK_0, VT_ADC_CTRL0_REG);
 533        if (ret >= 0)
 534                mask = (ret >> 8) | ((ret & 0xff) << 8);
 535        ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
 536        if (ret >= 0)
 537                mask |= (ret << 16);
 538        data->vsen_mask = mask;
 539
 540        /* CPU_TEMP attributes */
 541        ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG);
 542        if (ret < 0)
 543                return ret;
 544        data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4);
 545
 546        for (i = 0; i < FANCTL_MAX; i++) {
 547                ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i);
 548                if (ret < 0)
 549                        return ret;
 550                data->fan_mode[i] = ret;
 551        }
 552
 553        hwmon_dev =
 554                devm_hwmon_device_register_with_info(dev, client->name, data,
 555                                                     &nct7904_chip_info, NULL);
 556        return PTR_ERR_OR_ZERO(hwmon_dev);
 557}
 558
 559static const struct i2c_device_id nct7904_id[] = {
 560        {"nct7904", 0},
 561        {}
 562};
 563MODULE_DEVICE_TABLE(i2c, nct7904_id);
 564
 565static struct i2c_driver nct7904_driver = {
 566        .class = I2C_CLASS_HWMON,
 567        .driver = {
 568                .name = "nct7904",
 569        },
 570        .probe = nct7904_probe,
 571        .id_table = nct7904_id,
 572        .detect = nct7904_detect,
 573        .address_list = normal_i2c,
 574};
 575
 576module_i2c_driver(nct7904_driver);
 577
 578MODULE_AUTHOR("Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>");
 579MODULE_DESCRIPTION("Hwmon driver for NUVOTON NCT7904");
 580MODULE_LICENSE("GPL");
 581