linux/drivers/hwmon/pmbus/max20730.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Driver for MAX20710, MAX20730, MAX20734, and MAX20743 Integrated,
   4 * Step-Down Switching Regulators
   5 *
   6 * Copyright 2019 Google LLC.
   7 * Copyright 2020 Maxim Integrated
   8 */
   9
  10#include <linux/bits.h>
  11#include <linux/err.h>
  12#include <linux/i2c.h>
  13#include <linux/init.h>
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/mutex.h>
  17#include <linux/of_device.h>
  18#include <linux/pmbus.h>
  19#include <linux/util_macros.h>
  20#include "pmbus.h"
  21
  22enum chips {
  23        max20710,
  24        max20730,
  25        max20734,
  26        max20743
  27};
  28
  29struct max20730_data {
  30        enum chips id;
  31        struct pmbus_driver_info info;
  32        struct mutex lock;      /* Used to protect against parallel writes */
  33        u16 mfr_devset1;
  34};
  35
  36#define to_max20730_data(x)  container_of(x, struct max20730_data, info)
  37
  38#define MAX20730_MFR_DEVSET1    0xd2
  39
  40/*
  41 * Convert discreet value to direct data format. Strictly speaking, all passed
  42 * values are constants, so we could do that calculation manually. On the
  43 * downside, that would make the driver more difficult to maintain, so lets
  44 * use this approach.
  45 */
  46static u16 val_to_direct(int v, enum pmbus_sensor_classes class,
  47                         const struct pmbus_driver_info *info)
  48{
  49        int R = info->R[class] - 3;     /* take milli-units into account */
  50        int b = info->b[class] * 1000;
  51        long d;
  52
  53        d = v * info->m[class] + b;
  54        /*
  55         * R < 0 is true for all callers, so we don't need to bother
  56         * about the R > 0 case.
  57         */
  58        while (R < 0) {
  59                d = DIV_ROUND_CLOSEST(d, 10);
  60                R++;
  61        }
  62        return (u16)d;
  63}
  64
  65static long direct_to_val(u16 w, enum pmbus_sensor_classes class,
  66                          const struct pmbus_driver_info *info)
  67{
  68        int R = info->R[class] - 3;
  69        int b = info->b[class] * 1000;
  70        int m = info->m[class];
  71        long d = (s16)w;
  72
  73        if (m == 0)
  74                return 0;
  75
  76        while (R < 0) {
  77                d *= 10;
  78                R++;
  79        }
  80        d = (d - b) / m;
  81        return d;
  82}
  83
  84static u32 max_current[][5] = {
  85        [max20710] = { 6200, 8000, 9700, 11600 },
  86        [max20730] = { 13000, 16600, 20100, 23600 },
  87        [max20734] = { 21000, 27000, 32000, 38000 },
  88        [max20743] = { 18900, 24100, 29200, 34100 },
  89};
  90
  91static int max20730_read_word_data(struct i2c_client *client, int page,
  92                                   int phase, int reg)
  93{
  94        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
  95        const struct max20730_data *data = to_max20730_data(info);
  96        int ret = 0;
  97        u32 max_c;
  98
  99        switch (reg) {
 100        case PMBUS_OT_FAULT_LIMIT:
 101                switch ((data->mfr_devset1 >> 11) & 0x3) {
 102                case 0x0:
 103                        ret = val_to_direct(150000, PSC_TEMPERATURE, info);
 104                        break;
 105                case 0x1:
 106                        ret = val_to_direct(130000, PSC_TEMPERATURE, info);
 107                        break;
 108                default:
 109                        ret = -ENODATA;
 110                        break;
 111                }
 112                break;
 113        case PMBUS_IOUT_OC_FAULT_LIMIT:
 114                max_c = max_current[data->id][(data->mfr_devset1 >> 5) & 0x3];
 115                ret = val_to_direct(max_c, PSC_CURRENT_OUT, info);
 116                break;
 117        default:
 118                ret = -ENODATA;
 119                break;
 120        }
 121        return ret;
 122}
 123
 124static int max20730_write_word_data(struct i2c_client *client, int page,
 125                                    int reg, u16 word)
 126{
 127        struct pmbus_driver_info *info;
 128        struct max20730_data *data;
 129        u16 devset1;
 130        int ret = 0;
 131        int idx;
 132
 133        info = (struct pmbus_driver_info *)pmbus_get_driver_info(client);
 134        data = to_max20730_data(info);
 135
 136        mutex_lock(&data->lock);
 137        devset1 = data->mfr_devset1;
 138
 139        switch (reg) {
 140        case PMBUS_OT_FAULT_LIMIT:
 141                devset1 &= ~(BIT(11) | BIT(12));
 142                if (direct_to_val(word, PSC_TEMPERATURE, info) < 140000)
 143                        devset1 |= BIT(11);
 144                break;
 145        case PMBUS_IOUT_OC_FAULT_LIMIT:
 146                devset1 &= ~(BIT(5) | BIT(6));
 147
 148                idx = find_closest(direct_to_val(word, PSC_CURRENT_OUT, info),
 149                                   max_current[data->id], 4);
 150                devset1 |= (idx << 5);
 151                break;
 152        default:
 153                ret = -ENODATA;
 154                break;
 155        }
 156
 157        if (!ret && devset1 != data->mfr_devset1) {
 158                ret = i2c_smbus_write_word_data(client, MAX20730_MFR_DEVSET1,
 159                                                devset1);
 160                if (!ret) {
 161                        data->mfr_devset1 = devset1;
 162                        pmbus_clear_cache(client);
 163                }
 164        }
 165        mutex_unlock(&data->lock);
 166        return ret;
 167}
 168
 169static const struct pmbus_driver_info max20730_info[] = {
 170        [max20710] = {
 171                .pages = 1,
 172                .read_word_data = max20730_read_word_data,
 173                .write_word_data = max20730_write_word_data,
 174
 175                /* Source : Maxim AN6140 and AN6042 */
 176                .format[PSC_TEMPERATURE] = direct,
 177                .m[PSC_TEMPERATURE] = 21,
 178                .b[PSC_TEMPERATURE] = 5887,
 179                .R[PSC_TEMPERATURE] = -1,
 180
 181                .format[PSC_VOLTAGE_IN] = direct,
 182                .m[PSC_VOLTAGE_IN] = 3609,
 183                .b[PSC_VOLTAGE_IN] = 0,
 184                .R[PSC_VOLTAGE_IN] = -2,
 185
 186                .format[PSC_CURRENT_OUT] = direct,
 187                .m[PSC_CURRENT_OUT] = 153,
 188                .b[PSC_CURRENT_OUT] = 4976,
 189                .R[PSC_CURRENT_OUT] = -1,
 190
 191                .format[PSC_VOLTAGE_OUT] = linear,
 192
 193                .func[0] = PMBUS_HAVE_VIN |
 194                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
 195                        PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
 196                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
 197                        PMBUS_HAVE_STATUS_INPUT,
 198        },
 199        [max20730] = {
 200                .pages = 1,
 201                .read_word_data = max20730_read_word_data,
 202                .write_word_data = max20730_write_word_data,
 203
 204                /* Source : Maxim AN6042 */
 205                .format[PSC_TEMPERATURE] = direct,
 206                .m[PSC_TEMPERATURE] = 21,
 207                .b[PSC_TEMPERATURE] = 5887,
 208                .R[PSC_TEMPERATURE] = -1,
 209
 210                .format[PSC_VOLTAGE_IN] = direct,
 211                .m[PSC_VOLTAGE_IN] = 3609,
 212                .b[PSC_VOLTAGE_IN] = 0,
 213                .R[PSC_VOLTAGE_IN] = -2,
 214
 215                /*
 216                 * Values in the datasheet are adjusted for temperature and
 217                 * for the relationship between Vin and Vout.
 218                 * Unfortunately, the data sheet suggests that Vout measurement
 219                 * may be scaled with a resistor array. This is indeed the case
 220                 * at least on the evaulation boards. As a result, any in-driver
 221                 * adjustments would either be wrong or require elaborate means
 222                 * to configure the scaling. Instead of doing that, just report
 223                 * raw values and let userspace handle adjustments.
 224                 */
 225                .format[PSC_CURRENT_OUT] = direct,
 226                .m[PSC_CURRENT_OUT] = 153,
 227                .b[PSC_CURRENT_OUT] = 4976,
 228                .R[PSC_CURRENT_OUT] = -1,
 229
 230                .format[PSC_VOLTAGE_OUT] = linear,
 231
 232                .func[0] = PMBUS_HAVE_VIN |
 233                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
 234                        PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
 235                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
 236                        PMBUS_HAVE_STATUS_INPUT,
 237        },
 238        [max20734] = {
 239                .pages = 1,
 240                .read_word_data = max20730_read_word_data,
 241                .write_word_data = max20730_write_word_data,
 242
 243                /* Source : Maxim AN6209 */
 244                .format[PSC_TEMPERATURE] = direct,
 245                .m[PSC_TEMPERATURE] = 21,
 246                .b[PSC_TEMPERATURE] = 5887,
 247                .R[PSC_TEMPERATURE] = -1,
 248
 249                .format[PSC_VOLTAGE_IN] = direct,
 250                .m[PSC_VOLTAGE_IN] = 3592,
 251                .b[PSC_VOLTAGE_IN] = 0,
 252                .R[PSC_VOLTAGE_IN] = -2,
 253
 254                .format[PSC_CURRENT_OUT] = direct,
 255                .m[PSC_CURRENT_OUT] = 111,
 256                .b[PSC_CURRENT_OUT] = 3461,
 257                .R[PSC_CURRENT_OUT] = -1,
 258
 259                .format[PSC_VOLTAGE_OUT] = linear,
 260
 261                .func[0] = PMBUS_HAVE_VIN |
 262                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
 263                        PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
 264                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
 265                        PMBUS_HAVE_STATUS_INPUT,
 266        },
 267        [max20743] = {
 268                .pages = 1,
 269                .read_word_data = max20730_read_word_data,
 270                .write_word_data = max20730_write_word_data,
 271
 272                /* Source : Maxim AN6042 */
 273                .format[PSC_TEMPERATURE] = direct,
 274                .m[PSC_TEMPERATURE] = 21,
 275                .b[PSC_TEMPERATURE] = 5887,
 276                .R[PSC_TEMPERATURE] = -1,
 277
 278                .format[PSC_VOLTAGE_IN] = direct,
 279                .m[PSC_VOLTAGE_IN] = 3597,
 280                .b[PSC_VOLTAGE_IN] = 0,
 281                .R[PSC_VOLTAGE_IN] = -2,
 282
 283                .format[PSC_CURRENT_OUT] = direct,
 284                .m[PSC_CURRENT_OUT] = 95,
 285                .b[PSC_CURRENT_OUT] = 5014,
 286                .R[PSC_CURRENT_OUT] = -1,
 287
 288                .format[PSC_VOLTAGE_OUT] = linear,
 289
 290                .func[0] = PMBUS_HAVE_VIN |
 291                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
 292                        PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
 293                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
 294                        PMBUS_HAVE_STATUS_INPUT,
 295        },
 296};
 297
 298static int max20730_probe(struct i2c_client *client,
 299                          const struct i2c_device_id *id)
 300{
 301        struct device *dev = &client->dev;
 302        u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
 303        struct max20730_data *data;
 304        enum chips chip_id;
 305        int ret;
 306
 307        if (!i2c_check_functionality(client->adapter,
 308                                     I2C_FUNC_SMBUS_READ_BYTE_DATA |
 309                                     I2C_FUNC_SMBUS_READ_WORD_DATA |
 310                                     I2C_FUNC_SMBUS_BLOCK_DATA))
 311                return -ENODEV;
 312
 313        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
 314        if (ret < 0) {
 315                dev_err(&client->dev, "Failed to read Manufacturer ID\n");
 316                return ret;
 317        }
 318        if (ret != 5 || strncmp(buf, "MAXIM", 5)) {
 319                buf[ret] = '\0';
 320                dev_err(dev, "Unsupported Manufacturer ID '%s'\n", buf);
 321                return -ENODEV;
 322        }
 323
 324        /*
 325         * The chips support reading PMBUS_MFR_MODEL. On both MAX20730
 326         * and MAX20734, reading it returns M20743. Presumably that is
 327         * the reason why the command is not documented. Unfortunately,
 328         * that means that there is no reliable means to detect the chip.
 329         * However, we can at least detect the chip series. Compare
 330         * the returned value against 'M20743' and bail out if there is
 331         * a mismatch. If that doesn't work for all chips, we may have
 332         * to remove this check.
 333         */
 334        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
 335        if (ret < 0) {
 336                dev_err(dev, "Failed to read Manufacturer Model\n");
 337                return ret;
 338        }
 339        if (ret != 6 || strncmp(buf, "M20743", 6)) {
 340                buf[ret] = '\0';
 341                dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);
 342                return -ENODEV;
 343        }
 344
 345        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_REVISION, buf);
 346        if (ret < 0) {
 347                dev_err(dev, "Failed to read Manufacturer Revision\n");
 348                return ret;
 349        }
 350        if (ret != 1 || buf[0] != 'F') {
 351                buf[ret] = '\0';
 352                dev_err(dev, "Unsupported Manufacturer Revision '%s'\n", buf);
 353                return -ENODEV;
 354        }
 355
 356        if (client->dev.of_node)
 357                chip_id = (enum chips)of_device_get_match_data(dev);
 358        else
 359                chip_id = id->driver_data;
 360
 361        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 362        if (!data)
 363                return -ENOMEM;
 364        data->id = chip_id;
 365        mutex_init(&data->lock);
 366        memcpy(&data->info, &max20730_info[chip_id], sizeof(data->info));
 367
 368        ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET1);
 369        if (ret < 0)
 370                return ret;
 371        data->mfr_devset1 = ret;
 372
 373        return pmbus_do_probe(client, id, &data->info);
 374}
 375
 376static const struct i2c_device_id max20730_id[] = {
 377        { "max20710", max20710 },
 378        { "max20730", max20730 },
 379        { "max20734", max20734 },
 380        { "max20743", max20743 },
 381        { },
 382};
 383
 384MODULE_DEVICE_TABLE(i2c, max20730_id);
 385
 386static const struct of_device_id max20730_of_match[] = {
 387        { .compatible = "maxim,max20710", .data = (void *)max20710 },
 388        { .compatible = "maxim,max20730", .data = (void *)max20730 },
 389        { .compatible = "maxim,max20734", .data = (void *)max20734 },
 390        { .compatible = "maxim,max20743", .data = (void *)max20743 },
 391        { },
 392};
 393
 394MODULE_DEVICE_TABLE(of, max20730_of_match);
 395
 396static struct i2c_driver max20730_driver = {
 397        .driver = {
 398                .name = "max20730",
 399                .of_match_table = max20730_of_match,
 400        },
 401        .probe = max20730_probe,
 402        .remove = pmbus_do_remove,
 403        .id_table = max20730_id,
 404};
 405
 406module_i2c_driver(max20730_driver);
 407
 408MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
 409MODULE_DESCRIPTION("PMBus driver for Maxim MAX20710 / MAX20730 / MAX20734 / MAX20743");
 410MODULE_LICENSE("GPL");
 411