linux/drivers/hwmon/pmbus/lm25066.c
<<
>>
Prefs
   1/*
   2 * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066
   3 *
   4 * Copyright (c) 2011 Ericsson AB.
   5 * Copyright (c) 2013 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 "pmbus.h"
  29
  30enum chips { lm25056, lm25066, lm5064, lm5066 };
  31
  32#define LM25066_READ_VAUX               0xd0
  33#define LM25066_MFR_READ_IIN            0xd1
  34#define LM25066_MFR_READ_PIN            0xd2
  35#define LM25066_MFR_IIN_OC_WARN_LIMIT   0xd3
  36#define LM25066_MFR_PIN_OP_WARN_LIMIT   0xd4
  37#define LM25066_READ_PIN_PEAK           0xd5
  38#define LM25066_CLEAR_PIN_PEAK          0xd6
  39#define LM25066_DEVICE_SETUP            0xd9
  40#define LM25066_READ_AVG_VIN            0xdc
  41#define LM25066_READ_AVG_VOUT           0xdd
  42#define LM25066_READ_AVG_IIN            0xde
  43#define LM25066_READ_AVG_PIN            0xdf
  44
  45#define LM25066_DEV_SETUP_CL            (1 << 4)        /* Current limit */
  46
  47/* LM25056 only */
  48
  49#define LM25056_VAUX_OV_WARN_LIMIT      0xe3
  50#define LM25056_VAUX_UV_WARN_LIMIT      0xe4
  51
  52#define LM25056_MFR_STS_VAUX_OV_WARN    (1 << 1)
  53#define LM25056_MFR_STS_VAUX_UV_WARN    (1 << 0)
  54
  55struct __coeff {
  56        short m, b, R;
  57};
  58
  59#define PSC_CURRENT_IN_L        (PSC_NUM_CLASSES)
  60#define PSC_POWER_L             (PSC_NUM_CLASSES + 1)
  61
  62static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {
  63        [lm25056] = {
  64                [PSC_VOLTAGE_IN] = {
  65                        .m = 16296,
  66                        .R = -2,
  67                },
  68                [PSC_CURRENT_IN] = {
  69                        .m = 13797,
  70                        .R = -2,
  71                },
  72                [PSC_CURRENT_IN_L] = {
  73                        .m = 6726,
  74                        .R = -2,
  75                },
  76                [PSC_POWER] = {
  77                        .m = 5501,
  78                        .R = -3,
  79                },
  80                [PSC_POWER_L] = {
  81                        .m = 26882,
  82                        .R = -4,
  83                },
  84                [PSC_TEMPERATURE] = {
  85                        .m = 1580,
  86                        .b = -14500,
  87                        .R = -2,
  88                },
  89        },
  90        [lm25066] = {
  91                [PSC_VOLTAGE_IN] = {
  92                        .m = 22070,
  93                        .R = -2,
  94                },
  95                [PSC_VOLTAGE_OUT] = {
  96                        .m = 22070,
  97                        .R = -2,
  98                },
  99                [PSC_CURRENT_IN] = {
 100                        .m = 13661,
 101                        .R = -2,
 102                },
 103                [PSC_CURRENT_IN_L] = {
 104                        .m = 6852,
 105                        .R = -2,
 106                },
 107                [PSC_POWER] = {
 108                        .m = 736,
 109                        .R = -2,
 110                },
 111                [PSC_POWER_L] = {
 112                        .m = 369,
 113                        .R = -2,
 114                },
 115                [PSC_TEMPERATURE] = {
 116                        .m = 16,
 117                },
 118        },
 119        [lm5064] = {
 120                [PSC_VOLTAGE_IN] = {
 121                        .m = 4611,
 122                        .R = -2,
 123                },
 124                [PSC_VOLTAGE_OUT] = {
 125                        .m = 4621,
 126                        .R = -2,
 127                },
 128                [PSC_CURRENT_IN] = {
 129                        .m = 10742,
 130                        .R = -2,
 131                },
 132                [PSC_CURRENT_IN_L] = {
 133                        .m = 5456,
 134                        .R = -2,
 135                },
 136                [PSC_POWER] = {
 137                        .m = 1204,
 138                        .R = -3,
 139                },
 140                [PSC_POWER_L] = {
 141                        .m = 612,
 142                        .R = -3,
 143                },
 144                [PSC_TEMPERATURE] = {
 145                        .m = 16,
 146                },
 147        },
 148        [lm5066] = {
 149                [PSC_VOLTAGE_IN] = {
 150                        .m = 4587,
 151                        .R = -2,
 152                },
 153                [PSC_VOLTAGE_OUT] = {
 154                        .m = 4587,
 155                        .R = -2,
 156                },
 157                [PSC_CURRENT_IN] = {
 158                        .m = 10753,
 159                        .R = -2,
 160                },
 161                [PSC_CURRENT_IN_L] = {
 162                        .m = 5405,
 163                        .R = -2,
 164                },
 165                [PSC_POWER] = {
 166                        .m = 1204,
 167                        .R = -3,
 168                },
 169                [PSC_POWER_L] = {
 170                        .m = 605,
 171                        .R = -3,
 172                },
 173                [PSC_TEMPERATURE] = {
 174                        .m = 16,
 175                },
 176        },
 177};
 178
 179struct lm25066_data {
 180        int id;
 181        struct pmbus_driver_info info;
 182};
 183
 184#define to_lm25066_data(x)  container_of(x, struct lm25066_data, info)
 185
 186static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
 187{
 188        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 189        const struct lm25066_data *data = to_lm25066_data(info);
 190        int ret;
 191
 192        switch (reg) {
 193        case PMBUS_VIRT_READ_VMON:
 194                ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
 195                if (ret < 0)
 196                        break;
 197                /* Adjust returned value to match VIN coefficients */
 198                switch (data->id) {
 199                case lm25056:
 200                        /* VIN: 6.14 mV VAUX: 293 uV LSB */
 201                        ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 202                        break;
 203                case lm25066:
 204                        /* VIN: 4.54 mV VAUX: 283.2 uV LSB */
 205                        ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
 206                        break;
 207                case lm5064:
 208                        /* VIN: 4.53 mV VAUX: 700 uV LSB */
 209                        ret = DIV_ROUND_CLOSEST(ret * 70, 453);
 210                        break;
 211                case lm5066:
 212                        /* VIN: 2.18 mV VAUX: 725 uV LSB */
 213                        ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
 214                        break;
 215                }
 216                break;
 217        case PMBUS_READ_IIN:
 218                ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
 219                break;
 220        case PMBUS_READ_PIN:
 221                ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
 222                break;
 223        case PMBUS_IIN_OC_WARN_LIMIT:
 224                ret = pmbus_read_word_data(client, 0,
 225                                           LM25066_MFR_IIN_OC_WARN_LIMIT);
 226                break;
 227        case PMBUS_PIN_OP_WARN_LIMIT:
 228                ret = pmbus_read_word_data(client, 0,
 229                                           LM25066_MFR_PIN_OP_WARN_LIMIT);
 230                break;
 231        case PMBUS_VIRT_READ_VIN_AVG:
 232                ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
 233                break;
 234        case PMBUS_VIRT_READ_VOUT_AVG:
 235                ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
 236                break;
 237        case PMBUS_VIRT_READ_IIN_AVG:
 238                ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
 239                break;
 240        case PMBUS_VIRT_READ_PIN_AVG:
 241                ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
 242                break;
 243        case PMBUS_VIRT_READ_PIN_MAX:
 244                ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
 245                break;
 246        case PMBUS_VIRT_RESET_PIN_HISTORY:
 247                ret = 0;
 248                break;
 249        default:
 250                ret = -ENODATA;
 251                break;
 252        }
 253        return ret;
 254}
 255
 256static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
 257{
 258        int ret;
 259
 260        switch (reg) {
 261        case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 262                ret = pmbus_read_word_data(client, 0,
 263                                           LM25056_VAUX_UV_WARN_LIMIT);
 264                if (ret < 0)
 265                        break;
 266                /* Adjust returned value to match VIN coefficients */
 267                ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 268                break;
 269        case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 270                ret = pmbus_read_word_data(client, 0,
 271                                           LM25056_VAUX_OV_WARN_LIMIT);
 272                if (ret < 0)
 273                        break;
 274                /* Adjust returned value to match VIN coefficients */
 275                ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
 276                break;
 277        default:
 278                ret = lm25066_read_word_data(client, page, reg);
 279                break;
 280        }
 281        return ret;
 282}
 283
 284static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
 285{
 286        int ret, s;
 287
 288        switch (reg) {
 289        case PMBUS_VIRT_STATUS_VMON:
 290                ret = pmbus_read_byte_data(client, 0,
 291                                           PMBUS_STATUS_MFR_SPECIFIC);
 292                if (ret < 0)
 293                        break;
 294                s = 0;
 295                if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
 296                        s |= PB_VOLTAGE_UV_WARNING;
 297                if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
 298                        s |= PB_VOLTAGE_OV_WARNING;
 299                ret = s;
 300                break;
 301        default:
 302                ret = -ENODATA;
 303                break;
 304        }
 305        return ret;
 306}
 307
 308static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
 309                                   u16 word)
 310{
 311        int ret;
 312
 313        switch (reg) {
 314        case PMBUS_VOUT_UV_WARN_LIMIT:
 315        case PMBUS_OT_FAULT_LIMIT:
 316        case PMBUS_OT_WARN_LIMIT:
 317        case PMBUS_VIN_UV_WARN_LIMIT:
 318        case PMBUS_VIN_OV_WARN_LIMIT:
 319                word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 320                ret = pmbus_write_word_data(client, 0, reg, word);
 321                pmbus_clear_cache(client);
 322                break;
 323        case PMBUS_IIN_OC_WARN_LIMIT:
 324                word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 325                ret = pmbus_write_word_data(client, 0,
 326                                            LM25066_MFR_IIN_OC_WARN_LIMIT,
 327                                            word);
 328                pmbus_clear_cache(client);
 329                break;
 330        case PMBUS_PIN_OP_WARN_LIMIT:
 331                word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 332                ret = pmbus_write_word_data(client, 0,
 333                                            LM25066_MFR_PIN_OP_WARN_LIMIT,
 334                                            word);
 335                pmbus_clear_cache(client);
 336                break;
 337        case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
 338                /* Adjust from VIN coefficients (for LM25056) */
 339                word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
 340                word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 341                ret = pmbus_write_word_data(client, 0,
 342                                            LM25056_VAUX_UV_WARN_LIMIT, word);
 343                pmbus_clear_cache(client);
 344                break;
 345        case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
 346                /* Adjust from VIN coefficients (for LM25056) */
 347                word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
 348                word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
 349                ret = pmbus_write_word_data(client, 0,
 350                                            LM25056_VAUX_OV_WARN_LIMIT, word);
 351                pmbus_clear_cache(client);
 352                break;
 353        case PMBUS_VIRT_RESET_PIN_HISTORY:
 354                ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
 355                break;
 356        default:
 357                ret = -ENODATA;
 358                break;
 359        }
 360        return ret;
 361}
 362
 363static int lm25066_probe(struct i2c_client *client,
 364                          const struct i2c_device_id *id)
 365{
 366        int config;
 367        struct lm25066_data *data;
 368        struct pmbus_driver_info *info;
 369        struct __coeff *coeff;
 370
 371        if (!i2c_check_functionality(client->adapter,
 372                                     I2C_FUNC_SMBUS_READ_BYTE_DATA))
 373                return -ENODEV;
 374
 375        data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data),
 376                            GFP_KERNEL);
 377        if (!data)
 378                return -ENOMEM;
 379
 380        config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
 381        if (config < 0)
 382                return config;
 383
 384        data->id = id->driver_data;
 385        info = &data->info;
 386
 387        info->pages = 1;
 388        info->format[PSC_VOLTAGE_IN] = direct;
 389        info->format[PSC_VOLTAGE_OUT] = direct;
 390        info->format[PSC_CURRENT_IN] = direct;
 391        info->format[PSC_TEMPERATURE] = direct;
 392        info->format[PSC_POWER] = direct;
 393
 394        info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
 395          | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
 396          | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 397
 398        if (data->id == lm25056) {
 399                info->func[0] |= PMBUS_HAVE_STATUS_VMON;
 400                info->read_word_data = lm25056_read_word_data;
 401                info->read_byte_data = lm25056_read_byte_data;
 402        } else {
 403                info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
 404                info->read_word_data = lm25066_read_word_data;
 405        }
 406        info->write_word_data = lm25066_write_word_data;
 407
 408        coeff = &lm25066_coeff[data->id][0];
 409        info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
 410        info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
 411        info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
 412        info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
 413        info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
 414        info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
 415        info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
 416        info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
 417        info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
 418        info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
 419        info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
 420        info->b[PSC_POWER] = coeff[PSC_POWER].b;
 421        info->R[PSC_POWER] = coeff[PSC_POWER].R;
 422        if (config & LM25066_DEV_SETUP_CL) {
 423                info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
 424                info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
 425        } else {
 426                info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
 427                info->m[PSC_POWER] = coeff[PSC_POWER].m;
 428        }
 429
 430        return pmbus_do_probe(client, id, info);
 431}
 432
 433static const struct i2c_device_id lm25066_id[] = {
 434        {"lm25056", lm25056},
 435        {"lm25066", lm25066},
 436        {"lm5064", lm5064},
 437        {"lm5066", lm5066},
 438        { }
 439};
 440
 441MODULE_DEVICE_TABLE(i2c, lm25066_id);
 442
 443/* This is the driver that will be inserted */
 444static struct i2c_driver lm25066_driver = {
 445        .driver = {
 446                   .name = "lm25066",
 447                   },
 448        .probe = lm25066_probe,
 449        .remove = pmbus_do_remove,
 450        .id_table = lm25066_id,
 451};
 452
 453module_i2c_driver(lm25066_driver);
 454
 455MODULE_AUTHOR("Guenter Roeck");
 456MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066");
 457MODULE_LICENSE("GPL");
 458