306 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017 IBM Corp.4 *5 * Driver for the Nuvoton W83773G SMBus temperature sensor IC.6 * Supported models: W83773G7 */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.h>16#include <linux/regmap.h>17 18/* W83773 has 3 channels */19#define W83773_CHANNELS 320 21/* The W83773 registers */22#define W83773_CONVERSION_RATE_REG_READ 0x0423#define W83773_CONVERSION_RATE_REG_WRITE 0x0A24#define W83773_MANUFACTURER_ID_REG 0xFE25#define W83773_LOCAL_TEMP 0x0026 27static const u8 W83773_STATUS[2] = { 0x02, 0x17 };28 29static const u8 W83773_TEMP_LSB[2] = { 0x10, 0x25 };30static const u8 W83773_TEMP_MSB[2] = { 0x01, 0x24 };31 32static const u8 W83773_OFFSET_LSB[2] = { 0x12, 0x16 };33static const u8 W83773_OFFSET_MSB[2] = { 0x11, 0x15 };34 35/* this is the number of sensors in the device */36static const struct i2c_device_id w83773_id[] = {37 { "w83773g" },38 { }39};40 41MODULE_DEVICE_TABLE(i2c, w83773_id);42 43static const struct of_device_id __maybe_unused w83773_of_match[] = {44 {45 .compatible = "nuvoton,w83773g"46 },47 { },48};49MODULE_DEVICE_TABLE(of, w83773_of_match);50 51static inline long temp_of_local(s8 reg)52{53 return reg * 1000;54}55 56static inline long temp_of_remote(s8 hb, u8 lb)57{58 return (hb << 3 | lb >> 5) * 125;59}60 61static 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, ®val);67 if (ret < 0)68 return ret;69 70 *val = temp_of_local(regval);71 return 0;72}73 74static 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], ®val_high);81 if (ret < 0)82 return ret;83 84 ret = regmap_read(regmap, W83773_TEMP_LSB[index], ®val_low);85 if (ret < 0)86 return ret;87 88 *val = temp_of_remote(regval_high, regval_low);89 return 0;90}91 92static 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], ®val);98 if (ret < 0)99 return ret;100 101 *val = (regval & 0x04) >> 2;102 return 0;103}104 105static 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], ®val_high);112 if (ret < 0)113 return ret;114 115 ret = regmap_read(regmap, W83773_OFFSET_LSB[index], ®val_low);116 if (ret < 0)117 return ret;118 119 *val = temp_of_remote(regval_high, regval_low);120 return 0;121}122 123static 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 142static 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, ®val);148 if (ret < 0)149 return ret;150 151 *val = 16000 >> regval;152 return 0;153}154 155static int set_update_interval(struct regmap *regmap, long val)156{157 int rate;158 159 /*160 * For valid rates, interval can be calculated as161 * interval = (1 << (8 - rate)) * 62.5;162 * Rounded rate is therefore163 * rate = 8 - __fls(interval * 8 / (62.5 * 7));164 * Use clamp_val() to avoid overflows, and to ensure valid input165 * 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 172static 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 197static 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 211static 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 236static const struct hwmon_channel_info * const 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 NULL244};245 246static const struct hwmon_ops w83773_ops = {247 .is_visible = w83773_is_visible,248 .read = w83773_read,249 .write = w83773_write,250};251 252static const struct hwmon_chip_info w83773_chip_info = {253 .ops = &w83773_ops,254 .info = w83773_info,255};256 257static const struct regmap_config w83773_regmap_config = {258 .reg_bits = 8,259 .val_bits = 8,260};261 262static int w83773_probe(struct i2c_client *client)263{264 struct device *dev = &client->dev;265 struct device *hwmon_dev;266 struct regmap *regmap;267 int ret;268 269 regmap = devm_regmap_init_i2c(client, &w83773_regmap_config);270 if (IS_ERR(regmap)) {271 dev_err(dev, "failed to allocate register map\n");272 return PTR_ERR(regmap);273 }274 275 /* Set the conversion rate to 2 Hz */276 ret = regmap_write(regmap, W83773_CONVERSION_RATE_REG_WRITE, 0x05);277 if (ret < 0) {278 dev_err(&client->dev, "error writing config rate register\n");279 return ret;280 }281 282 i2c_set_clientdata(client, regmap);283 284 hwmon_dev = devm_hwmon_device_register_with_info(dev,285 client->name,286 regmap,287 &w83773_chip_info,288 NULL);289 return PTR_ERR_OR_ZERO(hwmon_dev);290}291 292static struct i2c_driver w83773_driver = {293 .driver = {294 .name = "w83773g",295 .of_match_table = of_match_ptr(w83773_of_match),296 },297 .probe = w83773_probe,298 .id_table = w83773_id,299};300 301module_i2c_driver(w83773_driver);302 303MODULE_AUTHOR("Lei YU <mine260309@gmail.com>");304MODULE_DESCRIPTION("W83773G temperature sensor driver");305MODULE_LICENSE("GPL");306