linux/drivers/hwmon/pmbus/tps544.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * TPS544B25 power regulator driver
   4 *
   5 * Copyright (C) 2019 Xilinx, Inc.
   6 *
   7 */
   8
   9#include <linux/delay.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/init.h>
  13#include <linux/err.h>
  14#include <linux/i2c.h>
  15#include <linux/regulator/driver.h>
  16#include "pmbus.h"
  17
  18#define TPS544_NUM_PAGES                1
  19
  20struct tps544_data {
  21        struct device *dev;
  22        u16 vout_min[TPS544_NUM_PAGES], vout_max[TPS544_NUM_PAGES];
  23        struct pmbus_driver_info info;
  24};
  25
  26struct vlut {
  27        int vol;
  28        u16 vloop;
  29        u16 v_ovfault;
  30        u16 v_ovwarn;
  31        u16 vmax;
  32        u16 mfr_vmin;
  33        u16 v_uvwarn;
  34        u16 v_uvfault;
  35};
  36
  37#if IS_ENABLED(CONFIG_SENSORS_TPS544_REGULATOR)
  38#define TPS544_MFR_VOUT_MIN             0xA4
  39#define TPS544_MFR_RESTORE_DEF_ALL      0x12
  40#define TPS544_MFR_IOUT_CAL_OFFSET      0x39
  41
  42#define TPS544_VOUTREAD_MULTIPLIER      1950
  43#define TPS544_IOUTREAD_MULTIPLIER      62500
  44#define TPS544_IOUTREAD_MASK            GENMASK(9, 0)
  45
  46#define TPS544_VOUT_LIMIT               5300000
  47
  48#define to_tps544_data(x) container_of(x, struct tps544_data, info)
  49
  50/*
  51 * This currently supports 3 voltage out buckets:
  52 * 0.5V to 1.3V
  53 * 1.3V to 2.6V
  54 * 2.6V to 5.3V
  55 * Any requested voltage will be mapped to one of these buckets and
  56 * VOUT will be programmed with 0.1V granularity.
  57 */
  58static const struct vlut tps544_vout[3] = {
  59        {500000, 0xF004, 0x0290, 0x0285, 0x0300, 0x0100, 0x00CD, 0x009A},
  60        {1300000, 0xF002, 0x059A, 0x0566, 0x0600, 0x0100, 0x0143, 0x0130},
  61        {2600000, 0xF001, 0x0B00, 0x0A9A, 0x0A00, 0x0100, 0x0143, 0x0130}
  62};
  63#endif
  64
  65static int tps544_read_word_data(struct i2c_client *client, int page, int reg)
  66{
  67        return pmbus_read_word_data(client, page, reg);
  68}
  69
  70static int tps544_read_byte_data(struct i2c_client *client, int page, int reg)
  71{
  72        return pmbus_read_byte_data(client, page, reg);
  73}
  74
  75static int tps544_write_byte(struct i2c_client *client, int page, u8 byte)
  76{
  77        return pmbus_write_byte(client, page, byte);
  78}
  79
  80static int tps544_write_word_data(struct i2c_client *client, int page,
  81                                  int reg, u16 word)
  82{
  83        int ret;
  84
  85        ret = pmbus_write_word_data(client, page, reg, word);
  86        /* TODO - Define new PMBUS virtual register entries for these */
  87
  88        return ret;
  89}
  90
  91#if IS_ENABLED(CONFIG_SENSORS_TPS544_REGULATOR)
  92static int tps544_regulator_get_voltage(struct regulator_dev *rdev)
  93{
  94        struct device *dev = rdev_get_dev(rdev);
  95        struct i2c_client *client = to_i2c_client(dev->parent);
  96        int page = 0;
  97
  98        return pmbus_read_word_data(client, page, PMBUS_READ_VOUT);
  99}
 100
 101static int tps544_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
 102                                        int max_uV, unsigned int *selector)
 103{
 104        struct device *dev = rdev_get_dev(rdev);
 105        struct i2c_client *client = to_i2c_client(dev->parent);
 106        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 107        struct tps544_data *data = to_tps544_data(info);
 108        int index, page = 0;
 109        u16 vout;
 110
 111        /* voltage will be set close to min value requested */
 112        vout = (u16)((min_uV * 512) / 1000000);
 113
 114        /* Check voltage bucket */
 115        if (min_uV >= tps544_vout[2].vol)
 116                index = 2;
 117        else if (min_uV >= tps544_vout[1].vol)
 118                index = 1;
 119        else if (min_uV >= tps544_vout[0].vol)
 120                index = 0;
 121        else
 122                return -EINVAL;
 123
 124        pmbus_write_word_data(client, page, PMBUS_VOUT_SCALE_LOOP,
 125                              tps544_vout[index].vloop);
 126        /* Use delay after setting scale loop; this is derived from testing */
 127        msleep(2000);
 128        pmbus_write_word_data(client, page, PMBUS_VOUT_OV_FAULT_LIMIT,
 129                              tps544_vout[index].v_ovfault);
 130        pmbus_write_word_data(client, page, PMBUS_VOUT_OV_WARN_LIMIT,
 131                              tps544_vout[index].v_ovwarn);
 132        pmbus_write_word_data(client, page, PMBUS_VOUT_MAX,
 133                              tps544_vout[index].vmax);
 134        pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, vout);
 135        tps544_write_word_data(client, page, TPS544_MFR_VOUT_MIN,
 136                               tps544_vout[index].mfr_vmin);
 137        pmbus_write_word_data(client, page, PMBUS_VOUT_UV_WARN_LIMIT,
 138                              tps544_vout[index].v_uvwarn);
 139        pmbus_write_word_data(client, page, PMBUS_VOUT_UV_FAULT_LIMIT,
 140                              tps544_vout[index].v_uvfault);
 141
 142        data->vout_min[page] = min_uV;
 143        data->vout_max[page] = max_uV;
 144
 145        return 0;
 146}
 147
 148static ssize_t tps544_setv_show(struct device *dev,
 149                                struct device_attribute *attr, char *buf)
 150{
 151        struct regulator_dev *rdev = dev_get_drvdata(dev);
 152        int vout;
 153
 154        vout = tps544_regulator_get_voltage(rdev) * TPS544_VOUTREAD_MULTIPLIER;
 155        return sprintf(buf, "%d\n", vout);
 156}
 157
 158static ssize_t tps544_setv_store(struct device *dev,
 159                                 struct device_attribute *attr,
 160                                 const char *buf, size_t count)
 161{
 162        struct regulator_dev *rdev = dev_get_drvdata(dev);
 163        int val;
 164        int err;
 165
 166        err = kstrtoint(buf, 0, &val);
 167        if (err)
 168                return err;
 169        if (val > TPS544_VOUT_LIMIT)
 170                return -EINVAL;
 171
 172        err = tps544_regulator_set_voltage(rdev, val, val, NULL);
 173        if (err)
 174                return err;
 175
 176        return count;
 177}
 178
 179static DEVICE_ATTR_RW(tps544_setv);
 180
 181static ssize_t tps544_restorev_store(struct device *dev,
 182                                     struct device_attribute *attr,
 183                                     const char *buf, size_t count)
 184{
 185        struct i2c_client *client = to_i2c_client(dev->parent);
 186        int err;
 187
 188        err = pmbus_write_byte(client, 0, TPS544_MFR_RESTORE_DEF_ALL);
 189        if (err)
 190                return err;
 191
 192        return count;
 193}
 194
 195static DEVICE_ATTR_WO(tps544_restorev);
 196
 197static ssize_t tps544_geti_show(struct device *dev,
 198                                struct device_attribute *attr, char *buf)
 199{
 200        struct i2c_client *client = to_i2c_client(dev->parent);
 201        u16 reg_iout;
 202
 203        reg_iout = pmbus_read_word_data(client, 0, PMBUS_READ_IOUT) &
 204                        TPS544_IOUTREAD_MASK;
 205
 206        return sprintf(buf, "%d\n", reg_iout * TPS544_IOUTREAD_MULTIPLIER);
 207}
 208
 209static DEVICE_ATTR_RO(tps544_geti);
 210
 211static ssize_t tps544_setcali_show(struct device *dev,
 212                                   struct device_attribute *attr, char *buf)
 213{
 214        struct i2c_client *client = to_i2c_client(dev->parent);
 215        int reg_cali;
 216
 217        reg_cali = pmbus_read_word_data(client, 0, TPS544_MFR_IOUT_CAL_OFFSET);
 218
 219        return sprintf(buf, "Current: 0x%x; Set value in hex to calibrate\n",
 220                       reg_cali);
 221}
 222
 223static ssize_t tps544_setcali_store(struct device *dev,
 224                                    struct device_attribute *attr,
 225                                    const char *buf, size_t count)
 226{
 227        struct i2c_client *client = to_i2c_client(dev->parent);
 228        u16 val;
 229        int err;
 230
 231        err = kstrtou16(buf, 0x0, &val);
 232        if (err)
 233                return err;
 234
 235        err = pmbus_write_word_data(client, 0, TPS544_MFR_IOUT_CAL_OFFSET, val);
 236        if (err)
 237                return err;
 238
 239        return (ssize_t)count;
 240}
 241
 242static DEVICE_ATTR_RW(tps544_setcali);
 243
 244static struct attribute *reg_attrs[] = {
 245        &dev_attr_tps544_setv.attr,
 246        &dev_attr_tps544_restorev.attr,
 247        &dev_attr_tps544_geti.attr,
 248        &dev_attr_tps544_setcali.attr,
 249        NULL,
 250};
 251
 252ATTRIBUTE_GROUPS(reg);
 253
 254static const struct regulator_desc tps544_reg_desc[] = {
 255        PMBUS_REGULATOR("vout", 0),
 256};
 257#endif /* CONFIG_SENSORS_TPS544_REGULATOR */
 258
 259static int tps544_probe(struct i2c_client *client,
 260                        const struct i2c_device_id *id)
 261{
 262        unsigned int i;
 263        struct device *dev = &client->dev;
 264        struct tps544_data *data;
 265        struct pmbus_driver_info *info;
 266#if IS_ENABLED(CONFIG_SENSORS_TPS544_REGULATOR)
 267        int ret;
 268        struct regulator_dev *rdev;
 269        struct regulator_config rconfig = { };
 270#endif
 271
 272        if (!i2c_check_functionality(client->adapter,
 273                                     I2C_FUNC_SMBUS_READ_WORD_DATA))
 274                return -ENODEV;
 275
 276        data = devm_kzalloc(dev, sizeof(struct tps544_data),
 277                            GFP_KERNEL);
 278        if (!data)
 279                return -ENOMEM;
 280
 281        data->dev = dev;
 282
 283        info = &data->info;
 284        info->write_word_data = tps544_write_word_data;
 285        /* TODO - remove these 3 hooks maybe unnecessary */
 286        info->write_byte = tps544_write_byte;
 287        info->read_word_data = tps544_read_word_data;
 288        info->read_byte_data = tps544_read_byte_data;
 289
 290        for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
 291                data->vout_min[i] = 0xffff;
 292
 293        info->pages = TPS544_NUM_PAGES;
 294        info->func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
 295
 296#if IS_ENABLED(CONFIG_SENSORS_TPS544_REGULATOR)
 297        rconfig.dev = dev;
 298        rconfig.driver_data = data;
 299        info->num_regulators = info->pages;
 300        info->reg_desc = tps544_reg_desc;
 301        if (info->num_regulators > (int)ARRAY_SIZE(tps544_reg_desc)) {
 302                dev_err(&client->dev, "num_regulators too large!");
 303                info->num_regulators = ARRAY_SIZE(tps544_reg_desc);
 304        }
 305
 306        rdev = devm_regulator_register(dev, tps544_reg_desc, &rconfig);
 307        if (IS_ERR(rdev)) {
 308                dev_err(dev, "Failed to register %s regulator\n",
 309                        info->reg_desc[0].name);
 310                return (int)PTR_ERR(rdev);
 311        }
 312
 313        ret = sysfs_create_groups(&rdev->dev.kobj, reg_groups);
 314        if (ret)
 315                return ret;
 316
 317        dev_set_drvdata(dev, rdev);
 318#endif
 319
 320        return pmbus_do_probe(client, id, info);
 321}
 322
 323static int tps544_remove(struct i2c_client *client)
 324{
 325#if IS_ENABLED(CONFIG_SENSORS_TPS544_REGULATOR)
 326        struct device *dev = &client->dev;
 327        struct regulator_dev *rdev = dev_get_drvdata(dev);
 328
 329        sysfs_remove_groups(&rdev->dev.kobj, reg_groups);
 330#endif
 331        pmbus_do_remove(client);
 332
 333        return 0;
 334}
 335
 336#ifdef CONFIG_OF
 337static const struct of_device_id tps544_of_match[] = {
 338        { .compatible = "ti,tps544" },
 339        { }
 340};
 341MODULE_DEVICE_TABLE(of, tps544_of_match);
 342#endif
 343
 344static const struct i2c_device_id tps544_id[] = {
 345        {"tps544", 0},
 346        {}
 347};
 348MODULE_DEVICE_TABLE(i2c, tps544_id);
 349
 350static struct i2c_driver tps544_driver = {
 351        .driver = {
 352                .name = "tps544",
 353                .of_match_table = of_match_ptr(tps544_of_match),
 354        },
 355        .probe = tps544_probe,
 356        .remove = tps544_remove,
 357        .id_table = tps544_id,
 358};
 359
 360module_i2c_driver(tps544_driver);
 361
 362MODULE_AUTHOR("Harini Katakam");
 363MODULE_DESCRIPTION("PMBus regulator driver for TPS544");
 364MODULE_LICENSE("GPL v2");
 365