linux/drivers/hwmon/pmbus/ltc2978.c
<<
>>
Prefs
   1/*
   2 * Hardware monitoring driver for LTC2978 and LTC3880
   3 *
   4 * Copyright (c) 2011 Ericsson AB.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/init.h>
  24#include <linux/err.h>
  25#include <linux/slab.h>
  26#include <linux/i2c.h>
  27#include "pmbus.h"
  28
  29enum chips { ltc2978, ltc3880 };
  30
  31/* LTC2978 and LTC3880 */
  32#define LTC2978_MFR_VOUT_PEAK           0xdd
  33#define LTC2978_MFR_VIN_PEAK            0xde
  34#define LTC2978_MFR_TEMPERATURE_PEAK    0xdf
  35#define LTC2978_MFR_SPECIAL_ID          0xe7
  36
  37/* LTC2978 only */
  38#define LTC2978_MFR_VOUT_MIN            0xfb
  39#define LTC2978_MFR_VIN_MIN             0xfc
  40#define LTC2978_MFR_TEMPERATURE_MIN     0xfd
  41
  42/* LTC3880 only */
  43#define LTC3880_MFR_IOUT_PEAK           0xd7
  44#define LTC3880_MFR_CLEAR_PEAKS         0xe3
  45#define LTC3880_MFR_TEMPERATURE2_PEAK   0xf4
  46
  47#define LTC2978_ID_REV1                 0x0121
  48#define LTC2978_ID_REV2                 0x0122
  49#define LTC3880_ID                      0x4000
  50#define LTC3880_ID_MASK                 0xff00
  51
  52/*
  53 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
  54 * happens pretty much each time chip data is updated. Raw peak data therefore
  55 * does not provide much value. To be able to provide useful peak data, keep an
  56 * internal cache of measured peak data, which is only cleared if an explicit
  57 * "clear peak" command is executed for the sensor in question.
  58 */
  59struct ltc2978_data {
  60        enum chips id;
  61        int vin_min, vin_max;
  62        int temp_min, temp_max;
  63        int vout_min[8], vout_max[8];
  64        int iout_max[2];
  65        int temp2_max[2];
  66        struct pmbus_driver_info info;
  67};
  68
  69#define to_ltc2978_data(x)  container_of(x, struct ltc2978_data, info)
  70
  71static inline int lin11_to_val(int data)
  72{
  73        s16 e = ((s16)data) >> 11;
  74        s32 m = (((s16)(data << 5)) >> 5);
  75
  76        /*
  77         * mantissa is 10 bit + sign, exponent adds up to 15 bit.
  78         * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
  79         */
  80        e += 6;
  81        return (e < 0 ? m >> -e : m << e);
  82}
  83
  84static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
  85                                         int reg)
  86{
  87        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
  88        struct ltc2978_data *data = to_ltc2978_data(info);
  89        int ret;
  90
  91        switch (reg) {
  92        case PMBUS_VIRT_READ_VIN_MAX:
  93                ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK);
  94                if (ret >= 0) {
  95                        if (lin11_to_val(ret) > lin11_to_val(data->vin_max))
  96                                data->vin_max = ret;
  97                        ret = data->vin_max;
  98                }
  99                break;
 100        case PMBUS_VIRT_READ_VOUT_MAX:
 101                ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
 102                if (ret >= 0) {
 103                        /*
 104                         * VOUT is 16 bit unsigned with fixed exponent,
 105                         * so we can compare it directly
 106                         */
 107                        if (ret > data->vout_max[page])
 108                                data->vout_max[page] = ret;
 109                        ret = data->vout_max[page];
 110                }
 111                break;
 112        case PMBUS_VIRT_READ_TEMP_MAX:
 113                ret = pmbus_read_word_data(client, page,
 114                                           LTC2978_MFR_TEMPERATURE_PEAK);
 115                if (ret >= 0) {
 116                        if (lin11_to_val(ret) > lin11_to_val(data->temp_max))
 117                                data->temp_max = ret;
 118                        ret = data->temp_max;
 119                }
 120                break;
 121        case PMBUS_VIRT_RESET_VOUT_HISTORY:
 122        case PMBUS_VIRT_RESET_VIN_HISTORY:
 123        case PMBUS_VIRT_RESET_TEMP_HISTORY:
 124                ret = 0;
 125                break;
 126        default:
 127                ret = -ENODATA;
 128                break;
 129        }
 130        return ret;
 131}
 132
 133static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
 134{
 135        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 136        struct ltc2978_data *data = to_ltc2978_data(info);
 137        int ret;
 138
 139        switch (reg) {
 140        case PMBUS_VIRT_READ_VIN_MIN:
 141                ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN);
 142                if (ret >= 0) {
 143                        if (lin11_to_val(ret) < lin11_to_val(data->vin_min))
 144                                data->vin_min = ret;
 145                        ret = data->vin_min;
 146                }
 147                break;
 148        case PMBUS_VIRT_READ_VOUT_MIN:
 149                ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
 150                if (ret >= 0) {
 151                        /*
 152                         * VOUT_MIN is known to not be supported on some lots
 153                         * of LTC2978 revision 1, and will return the maximum
 154                         * possible voltage if read. If VOUT_MAX is valid and
 155                         * lower than the reading of VOUT_MIN, use it instead.
 156                         */
 157                        if (data->vout_max[page] && ret > data->vout_max[page])
 158                                ret = data->vout_max[page];
 159                        if (ret < data->vout_min[page])
 160                                data->vout_min[page] = ret;
 161                        ret = data->vout_min[page];
 162                }
 163                break;
 164        case PMBUS_VIRT_READ_TEMP_MIN:
 165                ret = pmbus_read_word_data(client, page,
 166                                           LTC2978_MFR_TEMPERATURE_MIN);
 167                if (ret >= 0) {
 168                        if (lin11_to_val(ret)
 169                            < lin11_to_val(data->temp_min))
 170                                data->temp_min = ret;
 171                        ret = data->temp_min;
 172                }
 173                break;
 174        case PMBUS_VIRT_READ_IOUT_MAX:
 175        case PMBUS_VIRT_RESET_IOUT_HISTORY:
 176        case PMBUS_VIRT_READ_TEMP2_MAX:
 177        case PMBUS_VIRT_RESET_TEMP2_HISTORY:
 178                ret = -ENXIO;
 179                break;
 180        default:
 181                ret = ltc2978_read_word_data_common(client, page, reg);
 182                break;
 183        }
 184        return ret;
 185}
 186
 187static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
 188{
 189        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 190        struct ltc2978_data *data = to_ltc2978_data(info);
 191        int ret;
 192
 193        switch (reg) {
 194        case PMBUS_VIRT_READ_IOUT_MAX:
 195                ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK);
 196                if (ret >= 0) {
 197                        if (lin11_to_val(ret)
 198                            > lin11_to_val(data->iout_max[page]))
 199                                data->iout_max[page] = ret;
 200                        ret = data->iout_max[page];
 201                }
 202                break;
 203        case PMBUS_VIRT_READ_TEMP2_MAX:
 204                ret = pmbus_read_word_data(client, page,
 205                                           LTC3880_MFR_TEMPERATURE2_PEAK);
 206                if (ret >= 0) {
 207                        if (lin11_to_val(ret)
 208                            > lin11_to_val(data->temp2_max[page]))
 209                                data->temp2_max[page] = ret;
 210                        ret = data->temp2_max[page];
 211                }
 212                break;
 213        case PMBUS_VIRT_READ_VIN_MIN:
 214        case PMBUS_VIRT_READ_VOUT_MIN:
 215        case PMBUS_VIRT_READ_TEMP_MIN:
 216                ret = -ENXIO;
 217                break;
 218        case PMBUS_VIRT_RESET_IOUT_HISTORY:
 219        case PMBUS_VIRT_RESET_TEMP2_HISTORY:
 220                ret = 0;
 221                break;
 222        default:
 223                ret = ltc2978_read_word_data_common(client, page, reg);
 224                break;
 225        }
 226        return ret;
 227}
 228
 229static int ltc2978_clear_peaks(struct i2c_client *client, int page,
 230                               enum chips id)
 231{
 232        int ret;
 233
 234        if (id == ltc2978)
 235                ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
 236        else
 237                ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
 238
 239        return ret;
 240}
 241
 242static int ltc2978_write_word_data(struct i2c_client *client, int page,
 243                                    int reg, u16 word)
 244{
 245        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 246        struct ltc2978_data *data = to_ltc2978_data(info);
 247        int ret;
 248
 249        switch (reg) {
 250        case PMBUS_VIRT_RESET_IOUT_HISTORY:
 251                data->iout_max[page] = 0x7fff;
 252                ret = ltc2978_clear_peaks(client, page, data->id);
 253                break;
 254        case PMBUS_VIRT_RESET_TEMP2_HISTORY:
 255                data->temp2_max[page] = 0x7fff;
 256                ret = ltc2978_clear_peaks(client, page, data->id);
 257                break;
 258        case PMBUS_VIRT_RESET_VOUT_HISTORY:
 259                data->vout_min[page] = 0xffff;
 260                data->vout_max[page] = 0;
 261                ret = ltc2978_clear_peaks(client, page, data->id);
 262                break;
 263        case PMBUS_VIRT_RESET_VIN_HISTORY:
 264                data->vin_min = 0x7bff;
 265                data->vin_max = 0;
 266                ret = ltc2978_clear_peaks(client, page, data->id);
 267                break;
 268        case PMBUS_VIRT_RESET_TEMP_HISTORY:
 269                data->temp_min = 0x7bff;
 270                data->temp_max = 0x7fff;
 271                ret = ltc2978_clear_peaks(client, page, data->id);
 272                break;
 273        default:
 274                ret = -ENODATA;
 275                break;
 276        }
 277        return ret;
 278}
 279
 280static const struct i2c_device_id ltc2978_id[] = {
 281        {"ltc2978", ltc2978},
 282        {"ltc3880", ltc3880},
 283        {}
 284};
 285MODULE_DEVICE_TABLE(i2c, ltc2978_id);
 286
 287static int ltc2978_probe(struct i2c_client *client,
 288                         const struct i2c_device_id *id)
 289{
 290        int chip_id, i;
 291        struct ltc2978_data *data;
 292        struct pmbus_driver_info *info;
 293
 294        if (!i2c_check_functionality(client->adapter,
 295                                     I2C_FUNC_SMBUS_READ_WORD_DATA))
 296                return -ENODEV;
 297
 298        data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data),
 299                            GFP_KERNEL);
 300        if (!data)
 301                return -ENOMEM;
 302
 303        chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
 304        if (chip_id < 0)
 305                return chip_id;
 306
 307        if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
 308                data->id = ltc2978;
 309        } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
 310                data->id = ltc3880;
 311        } else {
 312                dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
 313                return -ENODEV;
 314        }
 315        if (data->id != id->driver_data)
 316                dev_warn(&client->dev,
 317                         "Device mismatch: Configured %s, detected %s\n",
 318                         id->name,
 319                         ltc2978_id[data->id].name);
 320
 321        info = &data->info;
 322        info->write_word_data = ltc2978_write_word_data;
 323
 324        data->vout_min[0] = 0xffff;
 325        data->vin_min = 0x7bff;
 326        data->temp_min = 0x7bff;
 327        data->temp_max = 0x7fff;
 328
 329        switch (id->driver_data) {
 330        case ltc2978:
 331                info->read_word_data = ltc2978_read_word_data;
 332                info->pages = 8;
 333                info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
 334                  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 335                  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 336                for (i = 1; i < 8; i++) {
 337                        info->func[i] = PMBUS_HAVE_VOUT
 338                          | PMBUS_HAVE_STATUS_VOUT;
 339                        data->vout_min[i] = 0xffff;
 340                }
 341                break;
 342        case ltc3880:
 343                info->read_word_data = ltc3880_read_word_data;
 344                info->pages = 2;
 345                info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
 346                  | PMBUS_HAVE_STATUS_INPUT
 347                  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 348                  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 349                  | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
 350                  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
 351                info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
 352                  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 353                  | PMBUS_HAVE_POUT
 354                  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 355                data->vout_min[1] = 0xffff;
 356                break;
 357        default:
 358                return -ENODEV;
 359        }
 360
 361        return pmbus_do_probe(client, id, info);
 362}
 363
 364/* This is the driver that will be inserted */
 365static struct i2c_driver ltc2978_driver = {
 366        .driver = {
 367                   .name = "ltc2978",
 368                   },
 369        .probe = ltc2978_probe,
 370        .remove = pmbus_do_remove,
 371        .id_table = ltc2978_id,
 372};
 373
 374module_i2c_driver(ltc2978_driver);
 375
 376MODULE_AUTHOR("Guenter Roeck");
 377MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
 378MODULE_LICENSE("GPL");
 379