162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * STTS751 sensor driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016-2017 Istituto Italiano di Tecnologia - RBCS - EDL 662306a36Sopenharmony_ci * Robotics, Brain and Cognitive Sciences department 762306a36Sopenharmony_ci * Electronic Design Laboratory 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Written by Andrea Merello <andrea.merello@gmail.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Based on LM95241 driver and LM90 driver 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/bitops.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <linux/hwmon.h> 1762306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1862306a36Sopenharmony_ci#include <linux/i2c.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/jiffies.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/mutex.h> 2462306a36Sopenharmony_ci#include <linux/property.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/sysfs.h> 2762306a36Sopenharmony_ci#include <linux/util_macros.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DEVNAME "stts751" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 3262306a36Sopenharmony_ci 0x48, 0x49, 0x38, 0x39, /* STTS751-0 */ 3362306a36Sopenharmony_ci 0x4A, 0x4B, 0x3A, 0x3B, /* STTS751-1 */ 3462306a36Sopenharmony_ci I2C_CLIENT_END }; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define STTS751_REG_TEMP_H 0x00 3762306a36Sopenharmony_ci#define STTS751_REG_STATUS 0x01 3862306a36Sopenharmony_ci#define STTS751_STATUS_TRIPT BIT(0) 3962306a36Sopenharmony_ci#define STTS751_STATUS_TRIPL BIT(5) 4062306a36Sopenharmony_ci#define STTS751_STATUS_TRIPH BIT(6) 4162306a36Sopenharmony_ci#define STTS751_REG_TEMP_L 0x02 4262306a36Sopenharmony_ci#define STTS751_REG_CONF 0x03 4362306a36Sopenharmony_ci#define STTS751_CONF_RES_MASK 0x0C 4462306a36Sopenharmony_ci#define STTS751_CONF_RES_SHIFT 2 4562306a36Sopenharmony_ci#define STTS751_CONF_EVENT_DIS BIT(7) 4662306a36Sopenharmony_ci#define STTS751_CONF_STOP BIT(6) 4762306a36Sopenharmony_ci#define STTS751_REG_RATE 0x04 4862306a36Sopenharmony_ci#define STTS751_REG_HLIM_H 0x05 4962306a36Sopenharmony_ci#define STTS751_REG_HLIM_L 0x06 5062306a36Sopenharmony_ci#define STTS751_REG_LLIM_H 0x07 5162306a36Sopenharmony_ci#define STTS751_REG_LLIM_L 0x08 5262306a36Sopenharmony_ci#define STTS751_REG_TLIM 0x20 5362306a36Sopenharmony_ci#define STTS751_REG_HYST 0x21 5462306a36Sopenharmony_ci#define STTS751_REG_SMBUS_TO 0x22 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define STTS751_REG_PROD_ID 0xFD 5762306a36Sopenharmony_ci#define STTS751_REG_MAN_ID 0xFE 5862306a36Sopenharmony_ci#define STTS751_REG_REV_ID 0xFF 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define STTS751_0_PROD_ID 0x00 6162306a36Sopenharmony_ci#define STTS751_1_PROD_ID 0x01 6262306a36Sopenharmony_ci#define ST_MAN_ID 0x53 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * Possible update intervals are (in mS): 6662306a36Sopenharmony_ci * 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 62.5, 31.25 6762306a36Sopenharmony_ci * However we are not going to complicate things too much and we stick to the 6862306a36Sopenharmony_ci * approx value in mS. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistatic const int stts751_intervals[] = { 7162306a36Sopenharmony_ci 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 63, 31 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const struct i2c_device_id stts751_id[] = { 7562306a36Sopenharmony_ci { "stts751", 0 }, 7662306a36Sopenharmony_ci { } 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused stts751_of_match[] = { 8062306a36Sopenharmony_ci { .compatible = "stts751" }, 8162306a36Sopenharmony_ci { }, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stts751_of_match); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct stts751_priv { 8662306a36Sopenharmony_ci struct device *dev; 8762306a36Sopenharmony_ci struct i2c_client *client; 8862306a36Sopenharmony_ci struct mutex access_lock; 8962306a36Sopenharmony_ci u8 interval; 9062306a36Sopenharmony_ci int res; 9162306a36Sopenharmony_ci int event_max, event_min; 9262306a36Sopenharmony_ci int therm; 9362306a36Sopenharmony_ci int hyst; 9462306a36Sopenharmony_ci bool smbus_timeout; 9562306a36Sopenharmony_ci int temp; 9662306a36Sopenharmony_ci unsigned long last_update, last_alert_update; 9762306a36Sopenharmony_ci u8 config; 9862306a36Sopenharmony_ci bool min_alert, max_alert, therm_trip; 9962306a36Sopenharmony_ci bool data_valid, alert_valid; 10062306a36Sopenharmony_ci bool notify_max, notify_min; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * These functions converts temperature from HW format to integer format and 10562306a36Sopenharmony_ci * vice-vers. They are (mostly) taken from lm90 driver. Unit is in mC. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic int stts751_to_deg(s16 hw_val) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return hw_val * 125 / 32; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic s32 stts751_to_hw(int val) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return DIV_ROUND_CLOSEST(val, 125) * 32; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int stts751_adjust_resolution(struct stts751_priv *priv) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci u8 res; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci switch (priv->interval) { 12262306a36Sopenharmony_ci case 9: 12362306a36Sopenharmony_ci /* 10 bits */ 12462306a36Sopenharmony_ci res = 0; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci case 8: 12762306a36Sopenharmony_ci /* 11 bits */ 12862306a36Sopenharmony_ci res = 1; 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci default: 13162306a36Sopenharmony_ci /* 12 bits */ 13262306a36Sopenharmony_ci res = 3; 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (priv->res == res) 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci priv->config &= ~STTS751_CONF_RES_MASK; 14062306a36Sopenharmony_ci priv->config |= res << STTS751_CONF_RES_SHIFT; 14162306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "setting res %d. config %x", 14262306a36Sopenharmony_ci res, priv->config); 14362306a36Sopenharmony_ci priv->res = res; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return i2c_smbus_write_byte_data(priv->client, 14662306a36Sopenharmony_ci STTS751_REG_CONF, priv->config); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int stts751_update_temp(struct stts751_priv *priv) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci s32 integer1, integer2, frac; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * There is a trick here, like in the lm90 driver. We have to read two 15562306a36Sopenharmony_ci * registers to get the sensor temperature, but we have to beware a 15662306a36Sopenharmony_ci * conversion could occur between the readings. We could use the 15762306a36Sopenharmony_ci * one-shot conversion register, but we don't want to do this (disables 15862306a36Sopenharmony_ci * hardware monitoring). So the solution used here is to read the high 15962306a36Sopenharmony_ci * byte once, then the low byte, then the high byte again. If the new 16062306a36Sopenharmony_ci * high byte matches the old one, then we have a valid reading. Else we 16162306a36Sopenharmony_ci * have to read the low byte again, and now we believe we have a correct 16262306a36Sopenharmony_ci * reading. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci integer1 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); 16562306a36Sopenharmony_ci if (integer1 < 0) { 16662306a36Sopenharmony_ci dev_dbg(&priv->client->dev, 16762306a36Sopenharmony_ci "I2C read failed (temp H). ret: %x\n", integer1); 16862306a36Sopenharmony_ci return integer1; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci frac = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_L); 17262306a36Sopenharmony_ci if (frac < 0) { 17362306a36Sopenharmony_ci dev_dbg(&priv->client->dev, 17462306a36Sopenharmony_ci "I2C read failed (temp L). ret: %x\n", frac); 17562306a36Sopenharmony_ci return frac; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci integer2 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); 17962306a36Sopenharmony_ci if (integer2 < 0) { 18062306a36Sopenharmony_ci dev_dbg(&priv->client->dev, 18162306a36Sopenharmony_ci "I2C 2nd read failed (temp H). ret: %x\n", integer2); 18262306a36Sopenharmony_ci return integer2; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (integer1 != integer2) { 18662306a36Sopenharmony_ci frac = i2c_smbus_read_byte_data(priv->client, 18762306a36Sopenharmony_ci STTS751_REG_TEMP_L); 18862306a36Sopenharmony_ci if (frac < 0) { 18962306a36Sopenharmony_ci dev_dbg(&priv->client->dev, 19062306a36Sopenharmony_ci "I2C 2nd read failed (temp L). ret: %x\n", 19162306a36Sopenharmony_ci frac); 19262306a36Sopenharmony_ci return frac; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci priv->temp = stts751_to_deg((integer1 << 8) | frac); 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int stts751_set_temp_reg16(struct stts751_priv *priv, int temp, 20162306a36Sopenharmony_ci u8 hreg, u8 lreg) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci s32 hwval; 20462306a36Sopenharmony_ci int ret; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci hwval = stts751_to_hw(temp); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(priv->client, hreg, hwval >> 8); 20962306a36Sopenharmony_ci if (ret) 21062306a36Sopenharmony_ci return ret; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return i2c_smbus_write_byte_data(priv->client, lreg, hwval & 0xff); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int stts751_set_temp_reg8(struct stts751_priv *priv, int temp, u8 reg) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci s32 hwval; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci hwval = stts751_to_hw(temp); 22062306a36Sopenharmony_ci return i2c_smbus_write_byte_data(priv->client, reg, hwval >> 8); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int stts751_read_reg16(struct stts751_priv *priv, int *temp, 22462306a36Sopenharmony_ci u8 hreg, u8 lreg) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int integer, frac; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci integer = i2c_smbus_read_byte_data(priv->client, hreg); 22962306a36Sopenharmony_ci if (integer < 0) 23062306a36Sopenharmony_ci return integer; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci frac = i2c_smbus_read_byte_data(priv->client, lreg); 23362306a36Sopenharmony_ci if (frac < 0) 23462306a36Sopenharmony_ci return frac; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci *temp = stts751_to_deg((integer << 8) | frac); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int stts751_read_reg8(struct stts751_priv *priv, int *temp, u8 reg) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci int integer; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci integer = i2c_smbus_read_byte_data(priv->client, reg); 24662306a36Sopenharmony_ci if (integer < 0) 24762306a36Sopenharmony_ci return integer; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci *temp = stts751_to_deg(integer << 8); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * Update alert flags without waiting for cache to expire. We detects alerts 25662306a36Sopenharmony_ci * immediately for the sake of the alert handler; we still need to deal with 25762306a36Sopenharmony_ci * caching to workaround the fact that alarm flags int the status register, 25862306a36Sopenharmony_ci * despite what the datasheet claims, gets always cleared on read. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistatic int stts751_update_alert(struct stts751_priv *priv) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int ret; 26362306a36Sopenharmony_ci bool conv_done; 26462306a36Sopenharmony_ci int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Add another 10% because if we run faster than the HW conversion 26862306a36Sopenharmony_ci * rate we will end up in reporting incorrectly alarms. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci cache_time += cache_time / 10; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_STATUS); 27362306a36Sopenharmony_ci if (ret < 0) 27462306a36Sopenharmony_ci return ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "status reg %x\n", ret); 27762306a36Sopenharmony_ci conv_done = ret & (STTS751_STATUS_TRIPH | STTS751_STATUS_TRIPL); 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * Reset the cache if the cache time expired, or if we are sure 28062306a36Sopenharmony_ci * we have valid data from a device conversion, or if we know 28162306a36Sopenharmony_ci * our cache has been never written. 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * Note that when the cache has been never written the point is 28462306a36Sopenharmony_ci * to correctly initialize the timestamp, rather than clearing 28562306a36Sopenharmony_ci * the cache values. 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * Note that updating the cache timestamp when we get an alarm flag 28862306a36Sopenharmony_ci * is required, otherwise we could incorrectly report alarms to be zero. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci if (time_after(jiffies, priv->last_alert_update + cache_time) || 29162306a36Sopenharmony_ci conv_done || !priv->alert_valid) { 29262306a36Sopenharmony_ci priv->max_alert = false; 29362306a36Sopenharmony_ci priv->min_alert = false; 29462306a36Sopenharmony_ci priv->alert_valid = true; 29562306a36Sopenharmony_ci priv->last_alert_update = jiffies; 29662306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "invalidating alert cache\n"); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci priv->max_alert |= !!(ret & STTS751_STATUS_TRIPH); 30062306a36Sopenharmony_ci priv->min_alert |= !!(ret & STTS751_STATUS_TRIPL); 30162306a36Sopenharmony_ci priv->therm_trip = !!(ret & STTS751_STATUS_TRIPT); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "max_alert: %d, min_alert: %d, therm_trip: %d\n", 30462306a36Sopenharmony_ci priv->max_alert, priv->min_alert, priv->therm_trip); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void stts751_alert(struct i2c_client *client, 31062306a36Sopenharmony_ci enum i2c_alert_protocol type, unsigned int data) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int ret; 31362306a36Sopenharmony_ci struct stts751_priv *priv = i2c_get_clientdata(client); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (type != I2C_PROTOCOL_SMBUS_ALERT) 31662306a36Sopenharmony_ci return; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci dev_dbg(&client->dev, "alert!"); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 32162306a36Sopenharmony_ci ret = stts751_update_alert(priv); 32262306a36Sopenharmony_ci if (ret < 0) { 32362306a36Sopenharmony_ci /* default to worst case */ 32462306a36Sopenharmony_ci priv->max_alert = true; 32562306a36Sopenharmony_ci priv->min_alert = true; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci dev_warn(priv->dev, 32862306a36Sopenharmony_ci "Alert received, but can't communicate to the device. Triggering all alarms!"); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (priv->max_alert) { 33262306a36Sopenharmony_ci if (priv->notify_max) 33362306a36Sopenharmony_ci dev_notice(priv->dev, "got alert for HIGH temperature"); 33462306a36Sopenharmony_ci priv->notify_max = false; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* unblock alert poll */ 33762306a36Sopenharmony_ci sysfs_notify(&priv->dev->kobj, NULL, "temp1_max_alarm"); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (priv->min_alert) { 34162306a36Sopenharmony_ci if (priv->notify_min) 34262306a36Sopenharmony_ci dev_notice(priv->dev, "got alert for LOW temperature"); 34362306a36Sopenharmony_ci priv->notify_min = false; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* unblock alert poll */ 34662306a36Sopenharmony_ci sysfs_notify(&priv->dev->kobj, NULL, "temp1_min_alarm"); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (priv->min_alert || priv->max_alert) 35062306a36Sopenharmony_ci kobject_uevent(&priv->dev->kobj, KOBJ_CHANGE); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int stts751_update(struct stts751_priv *priv) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (time_after(jiffies, priv->last_update + cache_time) || 36162306a36Sopenharmony_ci !priv->data_valid) { 36262306a36Sopenharmony_ci ret = stts751_update_temp(priv); 36362306a36Sopenharmony_ci if (ret) 36462306a36Sopenharmony_ci return ret; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ret = stts751_update_alert(priv); 36762306a36Sopenharmony_ci if (ret) 36862306a36Sopenharmony_ci return ret; 36962306a36Sopenharmony_ci priv->data_valid = true; 37062306a36Sopenharmony_ci priv->last_update = jiffies; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic ssize_t max_alarm_show(struct device *dev, 37762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int ret; 38062306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 38362306a36Sopenharmony_ci ret = stts751_update(priv); 38462306a36Sopenharmony_ci if (!ret) 38562306a36Sopenharmony_ci priv->notify_max = true; 38662306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 38762306a36Sopenharmony_ci if (ret < 0) 38862306a36Sopenharmony_ci return ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->max_alert); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic ssize_t min_alarm_show(struct device *dev, 39462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci int ret; 39762306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 40062306a36Sopenharmony_ci ret = stts751_update(priv); 40162306a36Sopenharmony_ci if (!ret) 40262306a36Sopenharmony_ci priv->notify_min = true; 40362306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 40462306a36Sopenharmony_ci if (ret < 0) 40562306a36Sopenharmony_ci return ret; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->min_alert); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic ssize_t input_show(struct device *dev, struct device_attribute *attr, 41162306a36Sopenharmony_ci char *buf) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int ret; 41462306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 41762306a36Sopenharmony_ci ret = stts751_update(priv); 41862306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 41962306a36Sopenharmony_ci if (ret < 0) 42062306a36Sopenharmony_ci return ret; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->temp); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic ssize_t therm_show(struct device *dev, struct device_attribute *attr, 42662306a36Sopenharmony_ci char *buf) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->therm); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic ssize_t therm_store(struct device *dev, struct device_attribute *attr, 43462306a36Sopenharmony_ci const char *buf, size_t count) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci int ret; 43762306a36Sopenharmony_ci long temp; 43862306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp) < 0) 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* HW works in range -64C to +127.937C */ 44462306a36Sopenharmony_ci temp = clamp_val(temp, -64000, 127937); 44562306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 44662306a36Sopenharmony_ci ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_TLIM); 44762306a36Sopenharmony_ci if (ret) 44862306a36Sopenharmony_ci goto exit; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "setting therm %ld", temp); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * hysteresis reg is relative to therm, so the HW does not need to be 45462306a36Sopenharmony_ci * adjusted, we need to update our local copy only. 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_ci priv->hyst = temp - (priv->therm - priv->hyst); 45762306a36Sopenharmony_ci priv->therm = temp; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciexit: 46062306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 46162306a36Sopenharmony_ci if (ret) 46262306a36Sopenharmony_ci return ret; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return count; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic ssize_t hyst_show(struct device *dev, struct device_attribute *attr, 46862306a36Sopenharmony_ci char *buf) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->hyst); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic ssize_t hyst_store(struct device *dev, struct device_attribute *attr, 47662306a36Sopenharmony_ci const char *buf, size_t count) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci int ret; 47962306a36Sopenharmony_ci long temp; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp) < 0) 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 48762306a36Sopenharmony_ci /* HW works in range -64C to +127.937C */ 48862306a36Sopenharmony_ci temp = clamp_val(temp, -64000, priv->therm); 48962306a36Sopenharmony_ci priv->hyst = temp; 49062306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "setting hyst %ld", temp); 49162306a36Sopenharmony_ci temp = priv->therm - temp; 49262306a36Sopenharmony_ci ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_HYST); 49362306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 49462306a36Sopenharmony_ci if (ret) 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return count; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic ssize_t therm_trip_show(struct device *dev, 50162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci int ret; 50462306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 50762306a36Sopenharmony_ci ret = stts751_update(priv); 50862306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 50962306a36Sopenharmony_ci if (ret < 0) 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->therm_trip); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic ssize_t max_show(struct device *dev, struct device_attribute *attr, 51662306a36Sopenharmony_ci char *buf) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->event_max); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic ssize_t max_store(struct device *dev, struct device_attribute *attr, 52462306a36Sopenharmony_ci const char *buf, size_t count) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci int ret; 52762306a36Sopenharmony_ci long temp; 52862306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp) < 0) 53162306a36Sopenharmony_ci return -EINVAL; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 53462306a36Sopenharmony_ci /* HW works in range -64C to +127.937C */ 53562306a36Sopenharmony_ci temp = clamp_val(temp, priv->event_min, 127937); 53662306a36Sopenharmony_ci ret = stts751_set_temp_reg16(priv, temp, 53762306a36Sopenharmony_ci STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); 53862306a36Sopenharmony_ci if (ret) 53962306a36Sopenharmony_ci goto exit; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "setting event max %ld", temp); 54262306a36Sopenharmony_ci priv->event_max = temp; 54362306a36Sopenharmony_ci ret = count; 54462306a36Sopenharmony_ciexit: 54562306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 54662306a36Sopenharmony_ci return ret; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic ssize_t min_show(struct device *dev, struct device_attribute *attr, 55062306a36Sopenharmony_ci char *buf) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", priv->event_min); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic ssize_t min_store(struct device *dev, struct device_attribute *attr, 55862306a36Sopenharmony_ci const char *buf, size_t count) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci int ret; 56162306a36Sopenharmony_ci long temp; 56262306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp) < 0) 56562306a36Sopenharmony_ci return -EINVAL; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 56862306a36Sopenharmony_ci /* HW works in range -64C to +127.937C */ 56962306a36Sopenharmony_ci temp = clamp_val(temp, -64000, priv->event_max); 57062306a36Sopenharmony_ci ret = stts751_set_temp_reg16(priv, temp, 57162306a36Sopenharmony_ci STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci goto exit; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "setting event min %ld", temp); 57662306a36Sopenharmony_ci priv->event_min = temp; 57762306a36Sopenharmony_ci ret = count; 57862306a36Sopenharmony_ciexit: 57962306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 58062306a36Sopenharmony_ci return ret; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic ssize_t interval_show(struct device *dev, 58462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 58962306a36Sopenharmony_ci stts751_intervals[priv->interval]); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic ssize_t interval_store(struct device *dev, 59362306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 59462306a36Sopenharmony_ci size_t count) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci unsigned long val; 59762306a36Sopenharmony_ci int idx; 59862306a36Sopenharmony_ci int ret = count; 59962306a36Sopenharmony_ci struct stts751_priv *priv = dev_get_drvdata(dev); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 60262306a36Sopenharmony_ci return -EINVAL; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci idx = find_closest_descending(val, stts751_intervals, 60562306a36Sopenharmony_ci ARRAY_SIZE(stts751_intervals)); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "setting interval. req:%lu, idx: %d, val: %d", 60862306a36Sopenharmony_ci val, idx, stts751_intervals[idx]); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci mutex_lock(&priv->access_lock); 61162306a36Sopenharmony_ci if (priv->interval == idx) 61262306a36Sopenharmony_ci goto exit; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* 61562306a36Sopenharmony_ci * In early development stages I've become suspicious about the chip 61662306a36Sopenharmony_ci * starting to misbehave if I ever set, even briefly, an invalid 61762306a36Sopenharmony_ci * configuration. While I'm not sure this is really needed, be 61862306a36Sopenharmony_ci * conservative and set rate/resolution in such an order that avoids 61962306a36Sopenharmony_ci * passing through an invalid configuration. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* speed up: lower the resolution, then modify convrate */ 62362306a36Sopenharmony_ci if (priv->interval < idx) { 62462306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "lower resolution, then modify convrate"); 62562306a36Sopenharmony_ci priv->interval = idx; 62662306a36Sopenharmony_ci ret = stts751_adjust_resolution(priv); 62762306a36Sopenharmony_ci if (ret) 62862306a36Sopenharmony_ci goto exit; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(priv->client, STTS751_REG_RATE, idx); 63262306a36Sopenharmony_ci if (ret) 63362306a36Sopenharmony_ci goto exit; 63462306a36Sopenharmony_ci /* slow down: modify convrate, then raise resolution */ 63562306a36Sopenharmony_ci if (priv->interval != idx) { 63662306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "modify convrate, then raise resolution"); 63762306a36Sopenharmony_ci priv->interval = idx; 63862306a36Sopenharmony_ci ret = stts751_adjust_resolution(priv); 63962306a36Sopenharmony_ci if (ret) 64062306a36Sopenharmony_ci goto exit; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci ret = count; 64362306a36Sopenharmony_ciexit: 64462306a36Sopenharmony_ci mutex_unlock(&priv->access_lock); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return ret; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int stts751_detect(struct i2c_client *new_client, 65062306a36Sopenharmony_ci struct i2c_board_info *info) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct i2c_adapter *adapter = new_client->adapter; 65362306a36Sopenharmony_ci const char *name; 65462306a36Sopenharmony_ci int tmp; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 65762306a36Sopenharmony_ci return -ENODEV; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_MAN_ID); 66062306a36Sopenharmony_ci if (tmp != ST_MAN_ID) 66162306a36Sopenharmony_ci return -ENODEV; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* lower temperaure registers always have bits 0-3 set to zero */ 66462306a36Sopenharmony_ci tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_TEMP_L); 66562306a36Sopenharmony_ci if (tmp & 0xf) 66662306a36Sopenharmony_ci return -ENODEV; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_HLIM_L); 66962306a36Sopenharmony_ci if (tmp & 0xf) 67062306a36Sopenharmony_ci return -ENODEV; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_LLIM_L); 67362306a36Sopenharmony_ci if (tmp & 0xf) 67462306a36Sopenharmony_ci return -ENODEV; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* smbus timeout register always have bits 0-7 set to zero */ 67762306a36Sopenharmony_ci tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_SMBUS_TO); 67862306a36Sopenharmony_ci if (tmp & 0x7f) 67962306a36Sopenharmony_ci return -ENODEV; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_PROD_ID); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci switch (tmp) { 68462306a36Sopenharmony_ci case STTS751_0_PROD_ID: 68562306a36Sopenharmony_ci name = "STTS751-0"; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci case STTS751_1_PROD_ID: 68862306a36Sopenharmony_ci name = "STTS751-1"; 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci default: 69162306a36Sopenharmony_ci return -ENODEV; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci dev_dbg(&new_client->dev, "Chip %s detected", name); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci strscpy(info->type, stts751_id[0].name, I2C_NAME_SIZE); 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int stts751_read_chip_config(struct stts751_priv *priv) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci int ret; 70262306a36Sopenharmony_ci int tmp; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_CONF); 70562306a36Sopenharmony_ci if (ret < 0) 70662306a36Sopenharmony_ci return ret; 70762306a36Sopenharmony_ci priv->config = ret; 70862306a36Sopenharmony_ci priv->res = (ret & STTS751_CONF_RES_MASK) >> STTS751_CONF_RES_SHIFT; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_RATE); 71162306a36Sopenharmony_ci if (ret < 0) 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci if (ret >= ARRAY_SIZE(stts751_intervals)) { 71462306a36Sopenharmony_ci dev_err(priv->dev, "Unrecognized conversion rate 0x%x\n", ret); 71562306a36Sopenharmony_ci return -ENODEV; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci priv->interval = ret; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci ret = stts751_read_reg16(priv, &priv->event_max, 72062306a36Sopenharmony_ci STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); 72162306a36Sopenharmony_ci if (ret) 72262306a36Sopenharmony_ci return ret; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci ret = stts751_read_reg16(priv, &priv->event_min, 72562306a36Sopenharmony_ci STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); 72662306a36Sopenharmony_ci if (ret) 72762306a36Sopenharmony_ci return ret; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci ret = stts751_read_reg8(priv, &priv->therm, STTS751_REG_TLIM); 73062306a36Sopenharmony_ci if (ret) 73162306a36Sopenharmony_ci return ret; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci ret = stts751_read_reg8(priv, &tmp, STTS751_REG_HYST); 73462306a36Sopenharmony_ci if (ret) 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci priv->hyst = priv->therm - tmp; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, input, 0); 74262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, min, 0); 74362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, max, 0); 74462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, min_alarm, 0); 74562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, max_alarm, 0); 74662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit, therm, 0); 74762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, hyst, 0); 74862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, therm_trip, 0); 74962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(update_interval, interval, 0); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic struct attribute *stts751_attrs[] = { 75262306a36Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 75362306a36Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 75462306a36Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 75562306a36Sopenharmony_ci &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 75662306a36Sopenharmony_ci &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 75762306a36Sopenharmony_ci &sensor_dev_attr_temp1_crit.dev_attr.attr, 75862306a36Sopenharmony_ci &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, 75962306a36Sopenharmony_ci &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, 76062306a36Sopenharmony_ci &sensor_dev_attr_update_interval.dev_attr.attr, 76162306a36Sopenharmony_ci NULL 76262306a36Sopenharmony_ci}; 76362306a36Sopenharmony_ciATTRIBUTE_GROUPS(stts751); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic int stts751_probe(struct i2c_client *client) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct stts751_priv *priv; 76862306a36Sopenharmony_ci int ret; 76962306a36Sopenharmony_ci bool smbus_nto; 77062306a36Sopenharmony_ci int rev_id; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 77362306a36Sopenharmony_ci if (!priv) 77462306a36Sopenharmony_ci return -ENOMEM; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci priv->client = client; 77762306a36Sopenharmony_ci priv->notify_max = true; 77862306a36Sopenharmony_ci priv->notify_min = true; 77962306a36Sopenharmony_ci i2c_set_clientdata(client, priv); 78062306a36Sopenharmony_ci mutex_init(&priv->access_lock); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (device_property_present(&client->dev, 78362306a36Sopenharmony_ci "smbus-timeout-disable")) { 78462306a36Sopenharmony_ci smbus_nto = device_property_read_bool(&client->dev, 78562306a36Sopenharmony_ci "smbus-timeout-disable"); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, STTS751_REG_SMBUS_TO, 78862306a36Sopenharmony_ci smbus_nto ? 0 : 0x80); 78962306a36Sopenharmony_ci if (ret) 79062306a36Sopenharmony_ci return ret; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci rev_id = i2c_smbus_read_byte_data(client, STTS751_REG_REV_ID); 79462306a36Sopenharmony_ci if (rev_id < 0) 79562306a36Sopenharmony_ci return -ENODEV; 79662306a36Sopenharmony_ci if (rev_id != 0x1) { 79762306a36Sopenharmony_ci dev_dbg(&client->dev, "Chip revision 0x%x is untested\n", 79862306a36Sopenharmony_ci rev_id); 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ret = stts751_read_chip_config(priv); 80262306a36Sopenharmony_ci if (ret) 80362306a36Sopenharmony_ci return ret; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci priv->config &= ~(STTS751_CONF_STOP | STTS751_CONF_EVENT_DIS); 80662306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, STTS751_REG_CONF, priv->config); 80762306a36Sopenharmony_ci if (ret) 80862306a36Sopenharmony_ci return ret; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci priv->dev = devm_hwmon_device_register_with_groups(&client->dev, 81162306a36Sopenharmony_ci client->name, priv, 81262306a36Sopenharmony_ci stts751_groups); 81362306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(priv->dev); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, stts751_id); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic struct i2c_driver stts751_driver = { 81962306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 82062306a36Sopenharmony_ci .driver = { 82162306a36Sopenharmony_ci .name = DEVNAME, 82262306a36Sopenharmony_ci .of_match_table = of_match_ptr(stts751_of_match), 82362306a36Sopenharmony_ci }, 82462306a36Sopenharmony_ci .probe = stts751_probe, 82562306a36Sopenharmony_ci .id_table = stts751_id, 82662306a36Sopenharmony_ci .detect = stts751_detect, 82762306a36Sopenharmony_ci .alert = stts751_alert, 82862306a36Sopenharmony_ci .address_list = normal_i2c, 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cimodule_i2c_driver(stts751_driver); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ciMODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>"); 83462306a36Sopenharmony_ciMODULE_DESCRIPTION("STTS751 sensor driver"); 83562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 836