400 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * max1619.c - Part of lm_sensors, Linux kernel modules for hardware4 * monitoring5 * Copyright (C) 2003-2004 Oleksij Rempel <bug-track@fisher-privat.net>6 * Jean Delvare <jdelvare@suse.de>7 *8 * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim.9 * It reports up to two temperatures (its own plus up to10 * one external one). Complete datasheet can be11 * obtained from Maxim's website at:12 * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf13 */14 15#include <linux/err.h>16#include <linux/hwmon.h>17#include <linux/i2c.h>18#include <linux/init.h>19#include <linux/module.h>20#include <linux/regmap.h>21#include <linux/util_macros.h>22 23static const unsigned short normal_i2c[] = {24 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };25 26#define MAX1619_REG_LOCAL_TEMP 0x0027#define MAX1619_REG_REMOTE_TEMP 0x0128#define MAX1619_REG_STATUS 0x0229#define MAX1619_REG_CONFIG 0x0330#define MAX1619_REG_CONVRATE 0x0431#define MAX1619_REG_REMOTE_HIGH 0x0732#define MAX1619_REG_REMOTE_LOW 0x0833#define MAX1619_REG_REMOTE_CRIT 0x1034#define MAX1619_REG_REMOTE_CRIT_HYST 0x1135#define MAX1619_REG_MAN_ID 0xFE36#define MAX1619_REG_CHIP_ID 0xFF37 38static int get_alarms(struct regmap *regmap)39{40 static u32 regs[2] = { MAX1619_REG_STATUS, MAX1619_REG_CONFIG };41 u8 regdata[2];42 int ret;43 44 ret = regmap_multi_reg_read(regmap, regs, regdata, 2);45 if (ret)46 return ret;47 48 /* OVERT status bit may be reversed */49 if (!(regdata[1] & 0x20))50 regdata[0] ^= 0x02;51 52 return regdata[0] & 0x1e;53}54 55static int max1619_temp_read(struct regmap *regmap, u32 attr, int channel, long *val)56{57 int reg = -1, alarm_bit = 0;58 u32 temp;59 int ret;60 61 switch (attr) {62 case hwmon_temp_input:63 reg = channel ? MAX1619_REG_REMOTE_TEMP : MAX1619_REG_LOCAL_TEMP;64 break;65 case hwmon_temp_min:66 reg = MAX1619_REG_REMOTE_LOW;67 break;68 case hwmon_temp_max:69 reg = MAX1619_REG_REMOTE_HIGH;70 break;71 case hwmon_temp_crit:72 reg = MAX1619_REG_REMOTE_CRIT;73 break;74 case hwmon_temp_crit_hyst:75 reg = MAX1619_REG_REMOTE_CRIT_HYST;76 break;77 case hwmon_temp_min_alarm:78 alarm_bit = 3;79 break;80 case hwmon_temp_max_alarm:81 alarm_bit = 4;82 break;83 case hwmon_temp_crit_alarm:84 alarm_bit = 1;85 break;86 case hwmon_temp_fault:87 alarm_bit = 2;88 break;89 default:90 return -EOPNOTSUPP;91 }92 if (reg >= 0) {93 ret = regmap_read(regmap, reg, &temp);94 if (ret < 0)95 return ret;96 *val = sign_extend32(temp, 7) * 1000;97 } else {98 ret = get_alarms(regmap);99 if (ret < 0)100 return ret;101 *val = !!(ret & BIT(alarm_bit));102 }103 return 0;104}105 106static u16 update_intervals[] = { 16000, 8000, 4000, 2000, 1000, 500, 250, 125 };107 108static int max1619_chip_read(struct regmap *regmap, u32 attr, long *val)109{110 int alarms, ret;111 u32 regval;112 113 switch (attr) {114 case hwmon_chip_update_interval:115 ret = regmap_read(regmap, MAX1619_REG_CONVRATE, ®val);116 if (ret < 0)117 return ret;118 *val = update_intervals[regval & 7];119 break;120 case hwmon_chip_alarms:121 alarms = get_alarms(regmap);122 if (alarms < 0)123 return alarms;124 *val = alarms;125 break;126 default:127 return -EOPNOTSUPP;128 }129 return 0;130}131 132static int max1619_read(struct device *dev, enum hwmon_sensor_types type,133 u32 attr, int channel, long *val)134{135 struct regmap *regmap = dev_get_drvdata(dev);136 137 switch (type) {138 case hwmon_chip:139 return max1619_chip_read(regmap, attr, val);140 case hwmon_temp:141 return max1619_temp_read(regmap, attr, channel, val);142 default:143 return -EOPNOTSUPP;144 }145}146 147static int max1619_chip_write(struct regmap *regmap, u32 attr, long val)148{149 switch (attr) {150 case hwmon_chip_update_interval:151 val = find_closest_descending(val, update_intervals, ARRAY_SIZE(update_intervals));152 return regmap_write(regmap, MAX1619_REG_CONVRATE, val);153 default:154 return -EOPNOTSUPP;155 }156}157 158static int max1619_temp_write(struct regmap *regmap,159 u32 attr, int channel, long val)160{161 int reg;162 163 switch (attr) {164 case hwmon_temp_min:165 reg = MAX1619_REG_REMOTE_LOW;166 break;167 case hwmon_temp_max:168 reg = MAX1619_REG_REMOTE_HIGH;169 break;170 case hwmon_temp_crit:171 reg = MAX1619_REG_REMOTE_CRIT;172 break;173 case hwmon_temp_crit_hyst:174 reg = MAX1619_REG_REMOTE_CRIT_HYST;175 break;176 default:177 return -EOPNOTSUPP;178 }179 val = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);180 return regmap_write(regmap, reg, val);181}182 183static int max1619_write(struct device *dev, enum hwmon_sensor_types type,184 u32 attr, int channel, long val)185{186 struct regmap *regmap = dev_get_drvdata(dev);187 188 switch (type) {189 case hwmon_chip:190 return max1619_chip_write(regmap, attr, val);191 case hwmon_temp:192 return max1619_temp_write(regmap, attr, channel, val);193 default:194 return -EOPNOTSUPP;195 }196}197 198static umode_t max1619_is_visible(const void *_data, enum hwmon_sensor_types type,199 u32 attr, int channel)200{201 switch (type) {202 case hwmon_chip:203 switch (attr) {204 case hwmon_chip_update_interval:205 return 0644;206 case hwmon_chip_alarms:207 return 0444;208 default:209 break;210 }211 break;212 case hwmon_temp:213 switch (attr) {214 case hwmon_temp_input:215 return 0444;216 case hwmon_temp_min:217 case hwmon_temp_max:218 case hwmon_temp_crit:219 case hwmon_temp_crit_hyst:220 return 0644;221 case hwmon_temp_min_alarm:222 case hwmon_temp_max_alarm:223 case hwmon_temp_crit_alarm:224 case hwmon_temp_fault:225 return 0444;226 default:227 break;228 }229 break;230 default:231 break;232 }233 return 0;234}235 236static const struct hwmon_channel_info * const max1619_info[] = {237 HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS | HWMON_C_UPDATE_INTERVAL),238 HWMON_CHANNEL_INFO(temp,239 HWMON_T_INPUT,240 HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |241 HWMON_T_CRIT | HWMON_T_CRIT_HYST |242 HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |243 HWMON_T_CRIT_ALARM | HWMON_T_FAULT),244 NULL245};246 247static const struct hwmon_ops max1619_hwmon_ops = {248 .is_visible = max1619_is_visible,249 .read = max1619_read,250 .write = max1619_write,251};252 253static const struct hwmon_chip_info max1619_chip_info = {254 .ops = &max1619_hwmon_ops,255 .info = max1619_info,256};257 258/* Return 0 if detection is successful, -ENODEV otherwise */259static int max1619_detect(struct i2c_client *client,260 struct i2c_board_info *info)261{262 struct i2c_adapter *adapter = client->adapter;263 int regval;264 265 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))266 return -ENODEV;267 268 regval = i2c_smbus_read_byte_data(client, MAX1619_REG_CONFIG);269 if (regval < 0 || (regval & 0x03))270 return -ENODEV;271 regval = i2c_smbus_read_byte_data(client, MAX1619_REG_CONVRATE);272 if (regval < 0 || regval > 0x07)273 return -ENODEV;274 regval = i2c_smbus_read_byte_data(client, MAX1619_REG_STATUS);275 if (regval < 0 || (regval & 0x61))276 return -ENODEV;277 278 regval = i2c_smbus_read_byte_data(client, MAX1619_REG_MAN_ID);279 if (regval != 0x4d)280 return -ENODEV;281 regval = i2c_smbus_read_byte_data(client, MAX1619_REG_CHIP_ID);282 if (regval != 0x04)283 return -ENODEV;284 285 strscpy(info->type, "max1619", I2C_NAME_SIZE);286 287 return 0;288}289 290static int max1619_init_chip(struct regmap *regmap)291{292 int ret;293 294 ret = regmap_write(regmap, MAX1619_REG_CONVRATE, 5); /* 2 Hz */295 if (ret)296 return ret;297 298 /* Start conversions */299 return regmap_clear_bits(regmap, MAX1619_REG_CONFIG, 0x40);300}301 302/* regmap */303 304static int max1619_reg_read(void *context, unsigned int reg, unsigned int *val)305{306 int ret;307 308 ret = i2c_smbus_read_byte_data(context, reg);309 if (ret < 0)310 return ret;311 312 *val = ret;313 return 0;314}315 316static int max1619_reg_write(void *context, unsigned int reg, unsigned int val)317{318 int offset = reg < MAX1619_REG_REMOTE_CRIT ? 6 : 2;319 320 return i2c_smbus_write_byte_data(context, reg + offset, val);321}322 323static bool max1619_regmap_is_volatile(struct device *dev, unsigned int reg)324{325 return reg <= MAX1619_REG_STATUS;326}327 328static bool max1619_regmap_is_writeable(struct device *dev, unsigned int reg)329{330 return reg > MAX1619_REG_STATUS && reg <= MAX1619_REG_REMOTE_CRIT_HYST;331}332 333static const struct regmap_config max1619_regmap_config = {334 .reg_bits = 8,335 .val_bits = 8,336 .max_register = MAX1619_REG_REMOTE_CRIT_HYST,337 .cache_type = REGCACHE_MAPLE,338 .volatile_reg = max1619_regmap_is_volatile,339 .writeable_reg = max1619_regmap_is_writeable,340};341 342static const struct regmap_bus max1619_regmap_bus = {343 .reg_write = max1619_reg_write,344 .reg_read = max1619_reg_read,345};346 347static int max1619_probe(struct i2c_client *client)348{349 struct device *dev = &client->dev;350 struct device *hwmon_dev;351 struct regmap *regmap;352 int ret;353 354 regmap = devm_regmap_init(dev, &max1619_regmap_bus, client,355 &max1619_regmap_config);356 if (IS_ERR(regmap))357 return PTR_ERR(regmap);358 359 ret = max1619_init_chip(regmap);360 if (ret)361 return ret;362 363 hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,364 regmap, &max1619_chip_info, NULL);365 return PTR_ERR_OR_ZERO(hwmon_dev);366}367 368static const struct i2c_device_id max1619_id[] = {369 { "max1619" },370 { }371};372MODULE_DEVICE_TABLE(i2c, max1619_id);373 374#ifdef CONFIG_OF375static const struct of_device_id max1619_of_match[] = {376 { .compatible = "maxim,max1619", },377 {},378};379 380MODULE_DEVICE_TABLE(of, max1619_of_match);381#endif382 383static struct i2c_driver max1619_driver = {384 .class = I2C_CLASS_HWMON,385 .driver = {386 .name = "max1619",387 .of_match_table = of_match_ptr(max1619_of_match),388 },389 .probe = max1619_probe,390 .id_table = max1619_id,391 .detect = max1619_detect,392 .address_list = normal_i2c,393};394 395module_i2c_driver(max1619_driver);396 397MODULE_AUTHOR("Oleksij Rempel <bug-track@fisher-privat.net>, Jean Delvare <jdelvare@suse.de>");398MODULE_DESCRIPTION("MAX1619 sensor driver");399MODULE_LICENSE("GPL");400