root/drivers/hwmon/w83773g.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. temp_of_local
  2. temp_of_remote
  3. get_local_temp
  4. get_remote_temp
  5. get_fault
  6. get_offset
  7. set_offset
  8. get_update_interval
  9. set_update_interval
  10. w83773_read
  11. w83773_write
  12. w83773_is_visible
  13. w83773_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2017 IBM Corp.
   4  *
   5  * Driver for the Nuvoton W83773G SMBus temperature sensor IC.
   6  * Supported models: W83773G
   7  */
   8 
   9 #include <linux/module.h>
  10 #include <linux/init.h>
  11 #include <linux/i2c.h>
  12 #include <linux/hwmon.h>
  13 #include <linux/hwmon-sysfs.h>
  14 #include <linux/err.h>
  15 #include <linux/of_device.h>
  16 #include <linux/regmap.h>
  17 
  18 /* W83773 has 3 channels */
  19 #define W83773_CHANNELS                         3
  20 
  21 /* The W83773 registers */
  22 #define W83773_CONVERSION_RATE_REG_READ         0x04
  23 #define W83773_CONVERSION_RATE_REG_WRITE        0x0A
  24 #define W83773_MANUFACTURER_ID_REG              0xFE
  25 #define W83773_LOCAL_TEMP                       0x00
  26 
  27 static const u8 W83773_STATUS[2] = { 0x02, 0x17 };
  28 
  29 static const u8 W83773_TEMP_LSB[2] = { 0x10, 0x25 };
  30 static const u8 W83773_TEMP_MSB[2] = { 0x01, 0x24 };
  31 
  32 static const u8 W83773_OFFSET_LSB[2] = { 0x12, 0x16 };
  33 static const u8 W83773_OFFSET_MSB[2] = { 0x11, 0x15 };
  34 
  35 /* this is the number of sensors in the device */
  36 static const struct i2c_device_id w83773_id[] = {
  37         { "w83773g" },
  38         { }
  39 };
  40 
  41 MODULE_DEVICE_TABLE(i2c, w83773_id);
  42 
  43 static const struct of_device_id __maybe_unused w83773_of_match[] = {
  44         {
  45                 .compatible = "nuvoton,w83773g"
  46         },
  47         { },
  48 };
  49 MODULE_DEVICE_TABLE(of, w83773_of_match);
  50 
  51 static inline long temp_of_local(s8 reg)
  52 {
  53         return reg * 1000;
  54 }
  55 
  56 static inline long temp_of_remote(s8 hb, u8 lb)
  57 {
  58         return (hb << 3 | lb >> 5) * 125;
  59 }
  60 
  61 static int get_local_temp(struct regmap *regmap, long *val)
  62 {
  63         unsigned int regval;
  64         int ret;
  65 
  66         ret = regmap_read(regmap, W83773_LOCAL_TEMP, &regval);
  67         if (ret < 0)
  68                 return ret;
  69 
  70         *val = temp_of_local(regval);
  71         return 0;
  72 }
  73 
  74 static int get_remote_temp(struct regmap *regmap, int index, long *val)
  75 {
  76         unsigned int regval_high;
  77         unsigned int regval_low;
  78         int ret;
  79 
  80         ret = regmap_read(regmap, W83773_TEMP_MSB[index], &regval_high);
  81         if (ret < 0)
  82                 return ret;
  83 
  84         ret = regmap_read(regmap, W83773_TEMP_LSB[index], &regval_low);
  85         if (ret < 0)
  86                 return ret;
  87 
  88         *val = temp_of_remote(regval_high, regval_low);
  89         return 0;
  90 }
  91 
  92 static int get_fault(struct regmap *regmap, int index, long *val)
  93 {
  94         unsigned int regval;
  95         int ret;
  96 
  97         ret = regmap_read(regmap, W83773_STATUS[index], &regval);
  98         if (ret < 0)
  99                 return ret;
 100 
 101         *val = (regval & 0x04) >> 2;
 102         return 0;
 103 }
 104 
 105 static int get_offset(struct regmap *regmap, int index, long *val)
 106 {
 107         unsigned int regval_high;
 108         unsigned int regval_low;
 109         int ret;
 110 
 111         ret = regmap_read(regmap, W83773_OFFSET_MSB[index], &regval_high);
 112         if (ret < 0)
 113                 return ret;
 114 
 115         ret = regmap_read(regmap, W83773_OFFSET_LSB[index], &regval_low);
 116         if (ret < 0)
 117                 return ret;
 118 
 119         *val = temp_of_remote(regval_high, regval_low);
 120         return 0;
 121 }
 122 
 123 static int set_offset(struct regmap *regmap, int index, long val)
 124 {
 125         int ret;
 126         u8 high_byte;
 127         u8 low_byte;
 128 
 129         val = clamp_val(val, -127825, 127825);
 130         /* offset value equals to (high_byte << 3 | low_byte >> 5) * 125 */
 131         val /= 125;
 132         high_byte = val >> 3;
 133         low_byte = (val & 0x07) << 5;
 134 
 135         ret = regmap_write(regmap, W83773_OFFSET_MSB[index], high_byte);
 136         if (ret < 0)
 137                 return ret;
 138 
 139         return regmap_write(regmap, W83773_OFFSET_LSB[index], low_byte);
 140 }
 141 
 142 static int get_update_interval(struct regmap *regmap, long *val)
 143 {
 144         unsigned int regval;
 145         int ret;
 146 
 147         ret = regmap_read(regmap, W83773_CONVERSION_RATE_REG_READ, &regval);
 148         if (ret < 0)
 149                 return ret;
 150 
 151         *val = 16000 >> regval;
 152         return 0;
 153 }
 154 
 155 static int set_update_interval(struct regmap *regmap, long val)
 156 {
 157         int rate;
 158 
 159         /*
 160          * For valid rates, interval can be calculated as
 161          *      interval = (1 << (8 - rate)) * 62.5;
 162          * Rounded rate is therefore
 163          *      rate = 8 - __fls(interval * 8 / (62.5 * 7));
 164          * Use clamp_val() to avoid overflows, and to ensure valid input
 165          * for __fls.
 166          */
 167         val = clamp_val(val, 62, 16000) * 10;
 168         rate = 8 - __fls((val * 8 / (625 * 7)));
 169         return regmap_write(regmap, W83773_CONVERSION_RATE_REG_WRITE, rate);
 170 }
 171 
 172 static int w83773_read(struct device *dev, enum hwmon_sensor_types type,
 173                        u32 attr, int channel, long *val)
 174 {
 175         struct regmap *regmap = dev_get_drvdata(dev);
 176 
 177         if (type == hwmon_chip) {
 178                 if (attr == hwmon_chip_update_interval)
 179                         return get_update_interval(regmap, val);
 180                 return -EOPNOTSUPP;
 181         }
 182 
 183         switch (attr) {
 184         case hwmon_temp_input:
 185                 if (channel == 0)
 186                         return get_local_temp(regmap, val);
 187                 return get_remote_temp(regmap, channel - 1, val);
 188         case hwmon_temp_fault:
 189                 return get_fault(regmap, channel - 1, val);
 190         case hwmon_temp_offset:
 191                 return get_offset(regmap, channel - 1, val);
 192         default:
 193                 return -EOPNOTSUPP;
 194         }
 195 }
 196 
 197 static int w83773_write(struct device *dev, enum hwmon_sensor_types type,
 198                         u32 attr, int channel, long val)
 199 {
 200         struct regmap *regmap = dev_get_drvdata(dev);
 201 
 202         if (type == hwmon_chip && attr == hwmon_chip_update_interval)
 203                 return set_update_interval(regmap, val);
 204 
 205         if (type == hwmon_temp && attr == hwmon_temp_offset)
 206                 return set_offset(regmap, channel - 1, val);
 207 
 208         return -EOPNOTSUPP;
 209 }
 210 
 211 static umode_t w83773_is_visible(const void *data, enum hwmon_sensor_types type,
 212                                  u32 attr, int channel)
 213 {
 214         switch (type) {
 215         case hwmon_chip:
 216                 switch (attr) {
 217                 case hwmon_chip_update_interval:
 218                         return 0644;
 219                 }
 220                 break;
 221         case hwmon_temp:
 222                 switch (attr) {
 223                 case hwmon_temp_input:
 224                 case hwmon_temp_fault:
 225                         return 0444;
 226                 case hwmon_temp_offset:
 227                         return 0644;
 228                 }
 229                 break;
 230         default:
 231                 break;
 232         }
 233         return 0;
 234 }
 235 
 236 static const struct hwmon_channel_info *w83773_info[] = {
 237         HWMON_CHANNEL_INFO(chip,
 238                            HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
 239         HWMON_CHANNEL_INFO(temp,
 240                            HWMON_T_INPUT,
 241                            HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_OFFSET,
 242                            HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_OFFSET),
 243         NULL
 244 };
 245 
 246 static const struct hwmon_ops w83773_ops = {
 247         .is_visible = w83773_is_visible,
 248         .read = w83773_read,
 249         .write = w83773_write,
 250 };
 251 
 252 static const struct hwmon_chip_info w83773_chip_info = {
 253         .ops = &w83773_ops,
 254         .info = w83773_info,
 255 };
 256 
 257 static const struct regmap_config w83773_regmap_config = {
 258         .reg_bits = 8,
 259         .val_bits = 8,
 260 };
 261 
 262 static int w83773_probe(struct i2c_client *client,
 263                         const struct i2c_device_id *id)
 264 {
 265         struct device *dev = &client->dev;
 266         struct device *hwmon_dev;
 267         struct regmap *regmap;
 268         int ret;
 269 
 270         regmap = devm_regmap_init_i2c(client, &w83773_regmap_config);
 271         if (IS_ERR(regmap)) {
 272                 dev_err(dev, "failed to allocate register map\n");
 273                 return PTR_ERR(regmap);
 274         }
 275 
 276         /* Set the conversion rate to 2 Hz */
 277         ret = regmap_write(regmap, W83773_CONVERSION_RATE_REG_WRITE, 0x05);
 278         if (ret < 0) {
 279                 dev_err(&client->dev, "error writing config rate register\n");
 280                 return ret;
 281         }
 282 
 283         i2c_set_clientdata(client, regmap);
 284 
 285         hwmon_dev = devm_hwmon_device_register_with_info(dev,
 286                                                          client->name,
 287                                                          regmap,
 288                                                          &w83773_chip_info,
 289                                                          NULL);
 290         return PTR_ERR_OR_ZERO(hwmon_dev);
 291 }
 292 
 293 static struct i2c_driver w83773_driver = {
 294         .class = I2C_CLASS_HWMON,
 295         .driver = {
 296                 .name   = "w83773g",
 297                 .of_match_table = of_match_ptr(w83773_of_match),
 298         },
 299         .probe = w83773_probe,
 300         .id_table = w83773_id,
 301 };
 302 
 303 module_i2c_driver(w83773_driver);
 304 
 305 MODULE_AUTHOR("Lei YU <mine260309@gmail.com>");
 306 MODULE_DESCRIPTION("W83773G temperature sensor driver");
 307 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */