linux/drivers/hwmon/pmbus/zl6100.c
<<
>>
Prefs
   1/*
   2 * Hardware monitoring driver for ZL6100 and compatibles
   3 *
   4 * Copyright (c) 2011 Ericsson AB.
   5 * Copyright (c) 2012 Guenter Roeck
   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 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/init.h>
  25#include <linux/err.h>
  26#include <linux/slab.h>
  27#include <linux/i2c.h>
  28#include <linux/ktime.h>
  29#include <linux/delay.h>
  30#include "pmbus.h"
  31
  32enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
  33             zl9101, zl9117 };
  34
  35struct zl6100_data {
  36        int id;
  37        ktime_t access;         /* chip access time */
  38        int delay;              /* Delay between chip accesses in uS */
  39        struct pmbus_driver_info info;
  40};
  41
  42#define to_zl6100_data(x)  container_of(x, struct zl6100_data, info)
  43
  44#define ZL6100_MFR_CONFIG               0xd0
  45#define ZL6100_DEVICE_ID                0xe4
  46
  47#define ZL6100_MFR_XTEMP_ENABLE         (1 << 7)
  48
  49#define MFR_VMON_OV_FAULT_LIMIT         0xf5
  50#define MFR_VMON_UV_FAULT_LIMIT         0xf6
  51#define MFR_READ_VMON                   0xf7
  52
  53#define VMON_UV_WARNING                 (1 << 5)
  54#define VMON_OV_WARNING                 (1 << 4)
  55#define VMON_UV_FAULT                   (1 << 1)
  56#define VMON_OV_FAULT                   (1 << 0)
  57
  58#define ZL6100_WAIT_TIME                1000    /* uS   */
  59
  60static ushort delay = ZL6100_WAIT_TIME;
  61module_param(delay, ushort, 0644);
  62MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
  63
  64/* Convert linear sensor value to milli-units */
  65static long zl6100_l2d(s16 l)
  66{
  67        s16 exponent;
  68        s32 mantissa;
  69        long val;
  70
  71        exponent = l >> 11;
  72        mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;
  73
  74        val = mantissa;
  75
  76        /* scale result to milli-units */
  77        val = val * 1000L;
  78
  79        if (exponent >= 0)
  80                val <<= exponent;
  81        else
  82                val >>= -exponent;
  83
  84        return val;
  85}
  86
  87#define MAX_MANTISSA    (1023 * 1000)
  88#define MIN_MANTISSA    (511 * 1000)
  89
  90static u16 zl6100_d2l(long val)
  91{
  92        s16 exponent = 0, mantissa;
  93        bool negative = false;
  94
  95        /* simple case */
  96        if (val == 0)
  97                return 0;
  98
  99        if (val < 0) {
 100                negative = true;
 101                val = -val;
 102        }
 103
 104        /* Reduce large mantissa until it fits into 10 bit */
 105        while (val >= MAX_MANTISSA && exponent < 15) {
 106                exponent++;
 107                val >>= 1;
 108        }
 109        /* Increase small mantissa to improve precision */
 110        while (val < MIN_MANTISSA && exponent > -15) {
 111                exponent--;
 112                val <<= 1;
 113        }
 114
 115        /* Convert mantissa from milli-units to units */
 116        mantissa = DIV_ROUND_CLOSEST(val, 1000);
 117
 118        /* Ensure that resulting number is within range */
 119        if (mantissa > 0x3ff)
 120                mantissa = 0x3ff;
 121
 122        /* restore sign */
 123        if (negative)
 124                mantissa = -mantissa;
 125
 126        /* Convert to 5 bit exponent, 11 bit mantissa */
 127        return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
 128}
 129
 130/* Some chips need a delay between accesses */
 131static inline void zl6100_wait(const struct zl6100_data *data)
 132{
 133        if (data->delay) {
 134                s64 delta = ktime_us_delta(ktime_get(), data->access);
 135                if (delta < data->delay)
 136                        udelay(data->delay - delta);
 137        }
 138}
 139
 140static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
 141{
 142        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 143        struct zl6100_data *data = to_zl6100_data(info);
 144        int ret, vreg;
 145
 146        if (page > 0)
 147                return -ENXIO;
 148
 149        if (data->id == zl2005) {
 150                /*
 151                 * Limit register detection is not reliable on ZL2005.
 152                 * Make sure registers are not erroneously detected.
 153                 */
 154                switch (reg) {
 155                case PMBUS_VOUT_OV_WARN_LIMIT:
 156                case PMBUS_VOUT_UV_WARN_LIMIT:
 157                case PMBUS_IOUT_OC_WARN_LIMIT:
 158                        return -ENXIO;
 159                }
 160        }
 161
 162        switch (reg) {
 163        case PMBUS_VIRT_READ_VMON:
 164                vreg = MFR_READ_VMON;
 165                break;
 166        case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 167        case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
 168                vreg = MFR_VMON_OV_FAULT_LIMIT;
 169                break;
 170        case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 171        case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
 172                vreg = MFR_VMON_UV_FAULT_LIMIT;
 173                break;
 174        default:
 175                if (reg >= PMBUS_VIRT_BASE)
 176                        return -ENXIO;
 177                vreg = reg;
 178                break;
 179        }
 180
 181        zl6100_wait(data);
 182        ret = pmbus_read_word_data(client, page, vreg);
 183        data->access = ktime_get();
 184        if (ret < 0)
 185                return ret;
 186
 187        switch (reg) {
 188        case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 189                ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));
 190                break;
 191        case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 192                ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));
 193                break;
 194        }
 195
 196        return ret;
 197}
 198
 199static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
 200{
 201        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 202        struct zl6100_data *data = to_zl6100_data(info);
 203        int ret, status;
 204
 205        if (page > 0)
 206                return -ENXIO;
 207
 208        zl6100_wait(data);
 209
 210        switch (reg) {
 211        case PMBUS_VIRT_STATUS_VMON:
 212                ret = pmbus_read_byte_data(client, 0,
 213                                           PMBUS_STATUS_MFR_SPECIFIC);
 214                if (ret < 0)
 215                        break;
 216
 217                status = 0;
 218                if (ret & VMON_UV_WARNING)
 219                        status |= PB_VOLTAGE_UV_WARNING;
 220                if (ret & VMON_OV_WARNING)
 221                        status |= PB_VOLTAGE_OV_WARNING;
 222                if (ret & VMON_UV_FAULT)
 223                        status |= PB_VOLTAGE_UV_FAULT;
 224                if (ret & VMON_OV_FAULT)
 225                        status |= PB_VOLTAGE_OV_FAULT;
 226                ret = status;
 227                break;
 228        default:
 229                ret = pmbus_read_byte_data(client, page, reg);
 230                break;
 231        }
 232        data->access = ktime_get();
 233
 234        return ret;
 235}
 236
 237static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
 238                                  u16 word)
 239{
 240        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 241        struct zl6100_data *data = to_zl6100_data(info);
 242        int ret, vreg;
 243
 244        if (page > 0)
 245                return -ENXIO;
 246
 247        switch (reg) {
 248        case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 249                word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));
 250                vreg = MFR_VMON_OV_FAULT_LIMIT;
 251                pmbus_clear_cache(client);
 252                break;
 253        case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
 254                vreg = MFR_VMON_OV_FAULT_LIMIT;
 255                pmbus_clear_cache(client);
 256                break;
 257        case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 258                word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));
 259                vreg = MFR_VMON_UV_FAULT_LIMIT;
 260                pmbus_clear_cache(client);
 261                break;
 262        case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
 263                vreg = MFR_VMON_UV_FAULT_LIMIT;
 264                pmbus_clear_cache(client);
 265                break;
 266        default:
 267                if (reg >= PMBUS_VIRT_BASE)
 268                        return -ENXIO;
 269                vreg = reg;
 270        }
 271
 272        zl6100_wait(data);
 273        ret = pmbus_write_word_data(client, page, vreg, word);
 274        data->access = ktime_get();
 275
 276        return ret;
 277}
 278
 279static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
 280{
 281        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 282        struct zl6100_data *data = to_zl6100_data(info);
 283        int ret;
 284
 285        if (page > 0)
 286                return -ENXIO;
 287
 288        zl6100_wait(data);
 289        ret = pmbus_write_byte(client, page, value);
 290        data->access = ktime_get();
 291
 292        return ret;
 293}
 294
 295static const struct i2c_device_id zl6100_id[] = {
 296        {"bmr450", zl2005},
 297        {"bmr451", zl2005},
 298        {"bmr462", zl2008},
 299        {"bmr463", zl2008},
 300        {"bmr464", zl2008},
 301        {"zl2004", zl2004},
 302        {"zl2005", zl2005},
 303        {"zl2006", zl2006},
 304        {"zl2008", zl2008},
 305        {"zl2105", zl2105},
 306        {"zl2106", zl2106},
 307        {"zl6100", zl6100},
 308        {"zl6105", zl6105},
 309        {"zl9101", zl9101},
 310        {"zl9117", zl9117},
 311        { }
 312};
 313MODULE_DEVICE_TABLE(i2c, zl6100_id);
 314
 315static int zl6100_probe(struct i2c_client *client,
 316                        const struct i2c_device_id *id)
 317{
 318        int ret;
 319        struct zl6100_data *data;
 320        struct pmbus_driver_info *info;
 321        u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
 322        const struct i2c_device_id *mid;
 323
 324        if (!i2c_check_functionality(client->adapter,
 325                                     I2C_FUNC_SMBUS_READ_WORD_DATA
 326                                     | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
 327                return -ENODEV;
 328
 329        ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
 330                                        device_id);
 331        if (ret < 0) {
 332                dev_err(&client->dev, "Failed to read device ID\n");
 333                return ret;
 334        }
 335        device_id[ret] = '\0';
 336        dev_info(&client->dev, "Device ID %s\n", device_id);
 337
 338        mid = NULL;
 339        for (mid = zl6100_id; mid->name[0]; mid++) {
 340                if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
 341                        break;
 342        }
 343        if (!mid->name[0]) {
 344                dev_err(&client->dev, "Unsupported device\n");
 345                return -ENODEV;
 346        }
 347        if (id->driver_data != mid->driver_data)
 348                dev_notice(&client->dev,
 349                           "Device mismatch: Configured %s, detected %s\n",
 350                           id->name, mid->name);
 351
 352        data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data),
 353                            GFP_KERNEL);
 354        if (!data)
 355                return -ENOMEM;
 356
 357        data->id = mid->driver_data;
 358
 359        /*
 360         * According to information from the chip vendor, all currently
 361         * supported chips are known to require a wait time between I2C
 362         * accesses.
 363         */
 364        data->delay = delay;
 365
 366        /*
 367         * Since there was a direct I2C device access above, wait before
 368         * accessing the chip again.
 369         */
 370        data->access = ktime_get();
 371        zl6100_wait(data);
 372
 373        info = &data->info;
 374
 375        info->pages = 1;
 376        info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
 377          | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 378          | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 379          | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 380
 381        /*
 382         * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
 383         * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
 384         */
 385        if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
 386                info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
 387
 388        ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
 389        if (ret < 0)
 390                return ret;
 391
 392        if (ret & ZL6100_MFR_XTEMP_ENABLE)
 393                info->func[0] |= PMBUS_HAVE_TEMP2;
 394
 395        data->access = ktime_get();
 396        zl6100_wait(data);
 397
 398        info->read_word_data = zl6100_read_word_data;
 399        info->read_byte_data = zl6100_read_byte_data;
 400        info->write_word_data = zl6100_write_word_data;
 401        info->write_byte = zl6100_write_byte;
 402
 403        return pmbus_do_probe(client, mid, info);
 404}
 405
 406static struct i2c_driver zl6100_driver = {
 407        .driver = {
 408                   .name = "zl6100",
 409                   },
 410        .probe = zl6100_probe,
 411        .remove = pmbus_do_remove,
 412        .id_table = zl6100_id,
 413};
 414
 415module_i2c_driver(zl6100_driver);
 416
 417MODULE_AUTHOR("Guenter Roeck");
 418MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
 419MODULE_LICENSE("GPL");
 420