162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Texas Instruments TMP108 SMBus temperature sensor driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2016 John Muir <john@jmuir.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/hwmon.h> 1162306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/mutex.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/i2c.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/jiffies.h> 1862306a36Sopenharmony_ci#include <linux/regmap.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define DRIVER_NAME "tmp108" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define TMP108_REG_TEMP 0x00 2462306a36Sopenharmony_ci#define TMP108_REG_CONF 0x01 2562306a36Sopenharmony_ci#define TMP108_REG_TLOW 0x02 2662306a36Sopenharmony_ci#define TMP108_REG_THIGH 0x03 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define TMP108_TEMP_MIN_MC -50000 /* Minimum millicelcius. */ 2962306a36Sopenharmony_ci#define TMP108_TEMP_MAX_MC 127937 /* Maximum millicelcius. */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Configuration register bits. 3262306a36Sopenharmony_ci * Note: these bit definitions are byte swapped. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci#define TMP108_CONF_M0 0x0100 /* Sensor mode. */ 3562306a36Sopenharmony_ci#define TMP108_CONF_M1 0x0200 3662306a36Sopenharmony_ci#define TMP108_CONF_TM 0x0400 /* Thermostat mode. */ 3762306a36Sopenharmony_ci#define TMP108_CONF_FL 0x0800 /* Watchdog flag - TLOW */ 3862306a36Sopenharmony_ci#define TMP108_CONF_FH 0x1000 /* Watchdog flag - THIGH */ 3962306a36Sopenharmony_ci#define TMP108_CONF_CR0 0x2000 /* Conversion rate. */ 4062306a36Sopenharmony_ci#define TMP108_CONF_CR1 0x4000 4162306a36Sopenharmony_ci#define TMP108_CONF_ID 0x8000 4262306a36Sopenharmony_ci#define TMP108_CONF_HYS0 0x0010 /* Hysteresis. */ 4362306a36Sopenharmony_ci#define TMP108_CONF_HYS1 0x0020 4462306a36Sopenharmony_ci#define TMP108_CONF_POL 0x0080 /* Polarity of alert. */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* Defaults set by the hardware upon reset. */ 4762306a36Sopenharmony_ci#define TMP108_CONF_DEFAULTS (TMP108_CONF_CR0 | TMP108_CONF_TM |\ 4862306a36Sopenharmony_ci TMP108_CONF_HYS0 | TMP108_CONF_M1) 4962306a36Sopenharmony_ci/* These bits are read-only. */ 5062306a36Sopenharmony_ci#define TMP108_CONF_READ_ONLY (TMP108_CONF_FL | TMP108_CONF_FH |\ 5162306a36Sopenharmony_ci TMP108_CONF_ID) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define TMP108_CONF_MODE_MASK (TMP108_CONF_M0|TMP108_CONF_M1) 5462306a36Sopenharmony_ci#define TMP108_MODE_SHUTDOWN 0x0000 5562306a36Sopenharmony_ci#define TMP108_MODE_ONE_SHOT TMP108_CONF_M0 5662306a36Sopenharmony_ci#define TMP108_MODE_CONTINUOUS TMP108_CONF_M1 /* Default */ 5762306a36Sopenharmony_ci /* When M1 is set, M0 is ignored. */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define TMP108_CONF_CONVRATE_MASK (TMP108_CONF_CR0|TMP108_CONF_CR1) 6062306a36Sopenharmony_ci#define TMP108_CONVRATE_0P25HZ 0x0000 6162306a36Sopenharmony_ci#define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */ 6262306a36Sopenharmony_ci#define TMP108_CONVRATE_4HZ TMP108_CONF_CR1 6362306a36Sopenharmony_ci#define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1) 6662306a36Sopenharmony_ci#define TMP108_HYSTERESIS_0C 0x0000 6762306a36Sopenharmony_ci#define TMP108_HYSTERESIS_1C TMP108_CONF_HYS0 /* Default */ 6862306a36Sopenharmony_ci#define TMP108_HYSTERESIS_2C TMP108_CONF_HYS1 6962306a36Sopenharmony_ci#define TMP108_HYSTERESIS_4C (TMP108_CONF_HYS0|TMP108_CONF_HYS1) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct tmp108 { 7462306a36Sopenharmony_ci struct regmap *regmap; 7562306a36Sopenharmony_ci u16 orig_config; 7662306a36Sopenharmony_ci unsigned long ready_time; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* convert 12-bit TMP108 register value to milliCelsius */ 8062306a36Sopenharmony_cistatic inline int tmp108_temp_reg_to_mC(s16 val) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return (val & ~0x0f) * 1000 / 256; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* convert milliCelsius to left adjusted 12-bit TMP108 register value */ 8662306a36Sopenharmony_cistatic inline u16 tmp108_mC_to_temp_reg(int val) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci return (val * 256) / 1000; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int tmp108_read(struct device *dev, enum hwmon_sensor_types type, 9262306a36Sopenharmony_ci u32 attr, int channel, long *temp) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct tmp108 *tmp108 = dev_get_drvdata(dev); 9562306a36Sopenharmony_ci unsigned int regval; 9662306a36Sopenharmony_ci int err, hyst; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (type == hwmon_chip) { 9962306a36Sopenharmony_ci if (attr == hwmon_chip_update_interval) { 10062306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, TMP108_REG_CONF, 10162306a36Sopenharmony_ci ®val); 10262306a36Sopenharmony_ci if (err < 0) 10362306a36Sopenharmony_ci return err; 10462306a36Sopenharmony_ci switch (regval & TMP108_CONF_CONVRATE_MASK) { 10562306a36Sopenharmony_ci case TMP108_CONVRATE_0P25HZ: 10662306a36Sopenharmony_ci default: 10762306a36Sopenharmony_ci *temp = 4000; 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci case TMP108_CONVRATE_1HZ: 11062306a36Sopenharmony_ci *temp = 1000; 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci case TMP108_CONVRATE_4HZ: 11362306a36Sopenharmony_ci *temp = 250; 11462306a36Sopenharmony_ci break; 11562306a36Sopenharmony_ci case TMP108_CONVRATE_16HZ: 11662306a36Sopenharmony_ci *temp = 63; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci return -EOPNOTSUPP; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci switch (attr) { 12562306a36Sopenharmony_ci case hwmon_temp_input: 12662306a36Sopenharmony_ci /* Is it too early to return a conversion ? */ 12762306a36Sopenharmony_ci if (time_before(jiffies, tmp108->ready_time)) { 12862306a36Sopenharmony_ci dev_dbg(dev, "%s: Conversion not ready yet..\n", 12962306a36Sopenharmony_ci __func__); 13062306a36Sopenharmony_ci return -EAGAIN; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val); 13362306a36Sopenharmony_ci if (err < 0) 13462306a36Sopenharmony_ci return err; 13562306a36Sopenharmony_ci *temp = tmp108_temp_reg_to_mC(regval); 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci case hwmon_temp_min: 13862306a36Sopenharmony_ci case hwmon_temp_max: 13962306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, attr == hwmon_temp_min ? 14062306a36Sopenharmony_ci TMP108_REG_TLOW : TMP108_REG_THIGH, ®val); 14162306a36Sopenharmony_ci if (err < 0) 14262306a36Sopenharmony_ci return err; 14362306a36Sopenharmony_ci *temp = tmp108_temp_reg_to_mC(regval); 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci case hwmon_temp_min_alarm: 14662306a36Sopenharmony_ci case hwmon_temp_max_alarm: 14762306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val); 14862306a36Sopenharmony_ci if (err < 0) 14962306a36Sopenharmony_ci return err; 15062306a36Sopenharmony_ci *temp = !!(regval & (attr == hwmon_temp_min_alarm ? 15162306a36Sopenharmony_ci TMP108_CONF_FL : TMP108_CONF_FH)); 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case hwmon_temp_min_hyst: 15462306a36Sopenharmony_ci case hwmon_temp_max_hyst: 15562306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val); 15662306a36Sopenharmony_ci if (err < 0) 15762306a36Sopenharmony_ci return err; 15862306a36Sopenharmony_ci switch (regval & TMP108_CONF_HYSTERESIS_MASK) { 15962306a36Sopenharmony_ci case TMP108_HYSTERESIS_0C: 16062306a36Sopenharmony_ci default: 16162306a36Sopenharmony_ci hyst = 0; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci case TMP108_HYSTERESIS_1C: 16462306a36Sopenharmony_ci hyst = 1000; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci case TMP108_HYSTERESIS_2C: 16762306a36Sopenharmony_ci hyst = 2000; 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci case TMP108_HYSTERESIS_4C: 17062306a36Sopenharmony_ci hyst = 4000; 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, attr == hwmon_temp_min_hyst ? 17462306a36Sopenharmony_ci TMP108_REG_TLOW : TMP108_REG_THIGH, ®val); 17562306a36Sopenharmony_ci if (err < 0) 17662306a36Sopenharmony_ci return err; 17762306a36Sopenharmony_ci *temp = tmp108_temp_reg_to_mC(regval); 17862306a36Sopenharmony_ci if (attr == hwmon_temp_min_hyst) 17962306a36Sopenharmony_ci *temp += hyst; 18062306a36Sopenharmony_ci else 18162306a36Sopenharmony_ci *temp -= hyst; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci default: 18462306a36Sopenharmony_ci return -EOPNOTSUPP; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int tmp108_write(struct device *dev, enum hwmon_sensor_types type, 19162306a36Sopenharmony_ci u32 attr, int channel, long temp) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct tmp108 *tmp108 = dev_get_drvdata(dev); 19462306a36Sopenharmony_ci u32 regval, mask; 19562306a36Sopenharmony_ci int err; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (type == hwmon_chip) { 19862306a36Sopenharmony_ci if (attr == hwmon_chip_update_interval) { 19962306a36Sopenharmony_ci if (temp < 156) 20062306a36Sopenharmony_ci mask = TMP108_CONVRATE_16HZ; 20162306a36Sopenharmony_ci else if (temp < 625) 20262306a36Sopenharmony_ci mask = TMP108_CONVRATE_4HZ; 20362306a36Sopenharmony_ci else if (temp < 2500) 20462306a36Sopenharmony_ci mask = TMP108_CONVRATE_1HZ; 20562306a36Sopenharmony_ci else 20662306a36Sopenharmony_ci mask = TMP108_CONVRATE_0P25HZ; 20762306a36Sopenharmony_ci return regmap_update_bits(tmp108->regmap, 20862306a36Sopenharmony_ci TMP108_REG_CONF, 20962306a36Sopenharmony_ci TMP108_CONF_CONVRATE_MASK, 21062306a36Sopenharmony_ci mask); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci return -EOPNOTSUPP; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci switch (attr) { 21662306a36Sopenharmony_ci case hwmon_temp_min: 21762306a36Sopenharmony_ci case hwmon_temp_max: 21862306a36Sopenharmony_ci temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC); 21962306a36Sopenharmony_ci return regmap_write(tmp108->regmap, 22062306a36Sopenharmony_ci attr == hwmon_temp_min ? 22162306a36Sopenharmony_ci TMP108_REG_TLOW : TMP108_REG_THIGH, 22262306a36Sopenharmony_ci tmp108_mC_to_temp_reg(temp)); 22362306a36Sopenharmony_ci case hwmon_temp_min_hyst: 22462306a36Sopenharmony_ci case hwmon_temp_max_hyst: 22562306a36Sopenharmony_ci temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC); 22662306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, 22762306a36Sopenharmony_ci attr == hwmon_temp_min_hyst ? 22862306a36Sopenharmony_ci TMP108_REG_TLOW : TMP108_REG_THIGH, 22962306a36Sopenharmony_ci ®val); 23062306a36Sopenharmony_ci if (err < 0) 23162306a36Sopenharmony_ci return err; 23262306a36Sopenharmony_ci if (attr == hwmon_temp_min_hyst) 23362306a36Sopenharmony_ci temp -= tmp108_temp_reg_to_mC(regval); 23462306a36Sopenharmony_ci else 23562306a36Sopenharmony_ci temp = tmp108_temp_reg_to_mC(regval) - temp; 23662306a36Sopenharmony_ci if (temp < 500) 23762306a36Sopenharmony_ci mask = TMP108_HYSTERESIS_0C; 23862306a36Sopenharmony_ci else if (temp < 1500) 23962306a36Sopenharmony_ci mask = TMP108_HYSTERESIS_1C; 24062306a36Sopenharmony_ci else if (temp < 3000) 24162306a36Sopenharmony_ci mask = TMP108_HYSTERESIS_2C; 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci mask = TMP108_HYSTERESIS_4C; 24462306a36Sopenharmony_ci return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, 24562306a36Sopenharmony_ci TMP108_CONF_HYSTERESIS_MASK, mask); 24662306a36Sopenharmony_ci default: 24762306a36Sopenharmony_ci return -EOPNOTSUPP; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type, 25262306a36Sopenharmony_ci u32 attr, int channel) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci if (type == hwmon_chip && attr == hwmon_chip_update_interval) 25562306a36Sopenharmony_ci return 0644; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (type != hwmon_temp) 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci switch (attr) { 26162306a36Sopenharmony_ci case hwmon_temp_input: 26262306a36Sopenharmony_ci case hwmon_temp_min_alarm: 26362306a36Sopenharmony_ci case hwmon_temp_max_alarm: 26462306a36Sopenharmony_ci return 0444; 26562306a36Sopenharmony_ci case hwmon_temp_min: 26662306a36Sopenharmony_ci case hwmon_temp_max: 26762306a36Sopenharmony_ci case hwmon_temp_min_hyst: 26862306a36Sopenharmony_ci case hwmon_temp_max_hyst: 26962306a36Sopenharmony_ci return 0644; 27062306a36Sopenharmony_ci default: 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic const struct hwmon_channel_info * const tmp108_info[] = { 27662306a36Sopenharmony_ci HWMON_CHANNEL_INFO(chip, 27762306a36Sopenharmony_ci HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), 27862306a36Sopenharmony_ci HWMON_CHANNEL_INFO(temp, 27962306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | 28062306a36Sopenharmony_ci HWMON_T_MIN_HYST | HWMON_T_MAX_HYST | 28162306a36Sopenharmony_ci HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM), 28262306a36Sopenharmony_ci NULL 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic const struct hwmon_ops tmp108_hwmon_ops = { 28662306a36Sopenharmony_ci .is_visible = tmp108_is_visible, 28762306a36Sopenharmony_ci .read = tmp108_read, 28862306a36Sopenharmony_ci .write = tmp108_write, 28962306a36Sopenharmony_ci}; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic const struct hwmon_chip_info tmp108_chip_info = { 29262306a36Sopenharmony_ci .ops = &tmp108_hwmon_ops, 29362306a36Sopenharmony_ci .info = tmp108_info, 29462306a36Sopenharmony_ci}; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void tmp108_restore_config(void *data) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct tmp108 *tmp108 = data; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci regmap_write(tmp108->regmap, TMP108_REG_CONF, tmp108->orig_config); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic bool tmp108_is_writeable_reg(struct device *dev, unsigned int reg) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci return reg != TMP108_REG_TEMP; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci /* Configuration register must be volatile to enable FL and FH. */ 31162306a36Sopenharmony_ci return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic const struct regmap_config tmp108_regmap_config = { 31562306a36Sopenharmony_ci .reg_bits = 8, 31662306a36Sopenharmony_ci .val_bits = 16, 31762306a36Sopenharmony_ci .max_register = TMP108_REG_THIGH, 31862306a36Sopenharmony_ci .writeable_reg = tmp108_is_writeable_reg, 31962306a36Sopenharmony_ci .volatile_reg = tmp108_is_volatile_reg, 32062306a36Sopenharmony_ci .val_format_endian = REGMAP_ENDIAN_BIG, 32162306a36Sopenharmony_ci .cache_type = REGCACHE_MAPLE, 32262306a36Sopenharmony_ci .use_single_read = true, 32362306a36Sopenharmony_ci .use_single_write = true, 32462306a36Sopenharmony_ci}; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int tmp108_probe(struct i2c_client *client) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct device *dev = &client->dev; 32962306a36Sopenharmony_ci struct device *hwmon_dev; 33062306a36Sopenharmony_ci struct tmp108 *tmp108; 33162306a36Sopenharmony_ci int err; 33262306a36Sopenharmony_ci u32 config; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, 33562306a36Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA)) { 33662306a36Sopenharmony_ci dev_err(dev, 33762306a36Sopenharmony_ci "adapter doesn't support SMBus word transactions\n"); 33862306a36Sopenharmony_ci return -ENODEV; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL); 34262306a36Sopenharmony_ci if (!tmp108) 34362306a36Sopenharmony_ci return -ENOMEM; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci dev_set_drvdata(dev, tmp108); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci tmp108->regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); 34862306a36Sopenharmony_ci if (IS_ERR(tmp108->regmap)) { 34962306a36Sopenharmony_ci err = PTR_ERR(tmp108->regmap); 35062306a36Sopenharmony_ci dev_err(dev, "regmap init failed: %d", err); 35162306a36Sopenharmony_ci return err; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config); 35562306a36Sopenharmony_ci if (err < 0) { 35662306a36Sopenharmony_ci dev_err(dev, "error reading config register: %d", err); 35762306a36Sopenharmony_ci return err; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci tmp108->orig_config = config; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Only continuous mode is supported. */ 36262306a36Sopenharmony_ci config &= ~TMP108_CONF_MODE_MASK; 36362306a36Sopenharmony_ci config |= TMP108_MODE_CONTINUOUS; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Only comparator mode is supported. */ 36662306a36Sopenharmony_ci config &= ~TMP108_CONF_TM; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci err = regmap_write(tmp108->regmap, TMP108_REG_CONF, config); 36962306a36Sopenharmony_ci if (err < 0) { 37062306a36Sopenharmony_ci dev_err(dev, "error writing config register: %d", err); 37162306a36Sopenharmony_ci return err; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci tmp108->ready_time = jiffies; 37562306a36Sopenharmony_ci if ((tmp108->orig_config & TMP108_CONF_MODE_MASK) == 37662306a36Sopenharmony_ci TMP108_MODE_SHUTDOWN) 37762306a36Sopenharmony_ci tmp108->ready_time += 37862306a36Sopenharmony_ci msecs_to_jiffies(TMP108_CONVERSION_TIME_MS); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108); 38162306a36Sopenharmony_ci if (err) { 38262306a36Sopenharmony_ci dev_err(dev, "add action or reset failed: %d", err); 38362306a36Sopenharmony_ci return err; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 38762306a36Sopenharmony_ci tmp108, 38862306a36Sopenharmony_ci &tmp108_chip_info, 38962306a36Sopenharmony_ci NULL); 39062306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int tmp108_suspend(struct device *dev) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct tmp108 *tmp108 = dev_get_drvdata(dev); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, 39862306a36Sopenharmony_ci TMP108_CONF_MODE_MASK, TMP108_MODE_SHUTDOWN); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int tmp108_resume(struct device *dev) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct tmp108 *tmp108 = dev_get_drvdata(dev); 40462306a36Sopenharmony_ci int err; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, 40762306a36Sopenharmony_ci TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS); 40862306a36Sopenharmony_ci tmp108->ready_time = jiffies + 40962306a36Sopenharmony_ci msecs_to_jiffies(TMP108_CONVERSION_TIME_MS); 41062306a36Sopenharmony_ci return err; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic const struct i2c_device_id tmp108_i2c_ids[] = { 41662306a36Sopenharmony_ci { "tmp108", 0 }, 41762306a36Sopenharmony_ci { } 41862306a36Sopenharmony_ci}; 41962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci#ifdef CONFIG_OF 42262306a36Sopenharmony_cistatic const struct of_device_id tmp108_of_ids[] = { 42362306a36Sopenharmony_ci { .compatible = "ti,tmp108", }, 42462306a36Sopenharmony_ci {} 42562306a36Sopenharmony_ci}; 42662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tmp108_of_ids); 42762306a36Sopenharmony_ci#endif 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic struct i2c_driver tmp108_driver = { 43062306a36Sopenharmony_ci .driver = { 43162306a36Sopenharmony_ci .name = DRIVER_NAME, 43262306a36Sopenharmony_ci .pm = pm_sleep_ptr(&tmp108_dev_pm_ops), 43362306a36Sopenharmony_ci .of_match_table = of_match_ptr(tmp108_of_ids), 43462306a36Sopenharmony_ci }, 43562306a36Sopenharmony_ci .probe = tmp108_probe, 43662306a36Sopenharmony_ci .id_table = tmp108_i2c_ids, 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cimodule_i2c_driver(tmp108_driver); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ciMODULE_AUTHOR("John Muir <john@jmuir.com>"); 44262306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments TMP108 temperature sensor driver"); 44362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 444