18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lm90.c - Part of lm_sensors, Linux kernel modules for hardware 48c2ecf20Sopenharmony_ci * monitoring 58c2ecf20Sopenharmony_ci * Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the lm83 driver. The LM90 is a sensor chip made by National 88c2ecf20Sopenharmony_ci * Semiconductor. It reports up to two temperatures (its own plus up to 98c2ecf20Sopenharmony_ci * one external one) with a 0.125 deg resolution (1 deg for local 108c2ecf20Sopenharmony_ci * temperature) and a 3-4 deg accuracy. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This driver also supports the LM89 and LM99, two other sensor chips 138c2ecf20Sopenharmony_ci * made by National Semiconductor. Both have an increased remote 148c2ecf20Sopenharmony_ci * temperature measurement accuracy (1 degree), and the LM99 158c2ecf20Sopenharmony_ci * additionally shifts remote temperatures (measured and limits) by 16 168c2ecf20Sopenharmony_ci * degrees, which allows for higher temperatures measurement. 178c2ecf20Sopenharmony_ci * Note that there is no way to differentiate between both chips. 188c2ecf20Sopenharmony_ci * When device is auto-detected, the driver will assume an LM99. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * This driver also supports the LM86, another sensor chip made by 218c2ecf20Sopenharmony_ci * National Semiconductor. It is exactly similar to the LM90 except it 228c2ecf20Sopenharmony_ci * has a higher accuracy. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This driver also supports the ADM1032, a sensor chip made by Analog 258c2ecf20Sopenharmony_ci * Devices. That chip is similar to the LM90, with a few differences 268c2ecf20Sopenharmony_ci * that are not handled by this driver. Among others, it has a higher 278c2ecf20Sopenharmony_ci * accuracy than the LM90, much like the LM86 does. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor 308c2ecf20Sopenharmony_ci * chips made by Maxim. These chips are similar to the LM86. 318c2ecf20Sopenharmony_ci * Note that there is no easy way to differentiate between the three 328c2ecf20Sopenharmony_ci * variants. We use the device address to detect MAX6659, which will result 338c2ecf20Sopenharmony_ci * in a detection as max6657 if it is on address 0x4c. The extra address 348c2ecf20Sopenharmony_ci * and features of the MAX6659 are only supported if the chip is configured 358c2ecf20Sopenharmony_ci * explicitly as max6659, or if its address is not 0x4c. 368c2ecf20Sopenharmony_ci * These chips lack the remote temperature offset feature. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * This driver also supports the MAX6654 chip made by Maxim. This chip can be 398c2ecf20Sopenharmony_ci * at 9 different addresses, similar to MAX6680/MAX6681. The MAX6654 is similar 408c2ecf20Sopenharmony_ci * to MAX6657/MAX6658/MAX6659, but does not support critical temperature 418c2ecf20Sopenharmony_ci * limits. Extended range is available by setting the configuration register 428c2ecf20Sopenharmony_ci * accordingly, and is done during initialization. Extended precision is only 438c2ecf20Sopenharmony_ci * available at conversion rates of 1 Hz and slower. Note that extended 448c2ecf20Sopenharmony_ci * precision is not enabled by default, as this driver initializes all chips 458c2ecf20Sopenharmony_ci * to 2 Hz by design. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and 488c2ecf20Sopenharmony_ci * MAX6692 chips made by Maxim. These are again similar to the LM86, 498c2ecf20Sopenharmony_ci * but they use unsigned temperature values and can report temperatures 508c2ecf20Sopenharmony_ci * from 0 to 145 degrees. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * This driver also supports the MAX6680 and MAX6681, two other sensor 538c2ecf20Sopenharmony_ci * chips made by Maxim. These are quite similar to the other Maxim 548c2ecf20Sopenharmony_ci * chips. The MAX6680 and MAX6681 only differ in the pinout so they can 558c2ecf20Sopenharmony_ci * be treated identically. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * This driver also supports the MAX6695 and MAX6696, two other sensor 588c2ecf20Sopenharmony_ci * chips made by Maxim. These are also quite similar to other Maxim 598c2ecf20Sopenharmony_ci * chips, but support three temperature sensors instead of two. MAX6695 608c2ecf20Sopenharmony_ci * and MAX6696 only differ in the pinout so they can be treated identically. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as 638c2ecf20Sopenharmony_ci * NCT1008 from ON Semiconductor. The chips are supported in both compatibility 648c2ecf20Sopenharmony_ci * and extended mode. They are mostly compatible with LM90 except for a data 658c2ecf20Sopenharmony_ci * format difference for the temperature value registers. 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * This driver also supports the SA56004 from Philips. This device is 688c2ecf20Sopenharmony_ci * pin-compatible with the LM86, the ED/EDP parts are also address-compatible. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * This driver also supports the G781 from GMT. This device is compatible 718c2ecf20Sopenharmony_ci * with the ADM1032. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * This driver also supports TMP451 and TMP461 from Texas Instruments. 748c2ecf20Sopenharmony_ci * Those devices are supported in both compatibility and extended mode. 758c2ecf20Sopenharmony_ci * They are mostly compatible with ADT7461 except for local temperature 768c2ecf20Sopenharmony_ci * low byte register and max conversion rate. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Since the LM90 was the first chipset supported by this driver, most 798c2ecf20Sopenharmony_ci * comments will refer to this chipset, but are actually general and 808c2ecf20Sopenharmony_ci * concern all supported chipsets, unless mentioned otherwise. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#include <linux/module.h> 848c2ecf20Sopenharmony_ci#include <linux/init.h> 858c2ecf20Sopenharmony_ci#include <linux/slab.h> 868c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 878c2ecf20Sopenharmony_ci#include <linux/i2c.h> 888c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 898c2ecf20Sopenharmony_ci#include <linux/err.h> 908c2ecf20Sopenharmony_ci#include <linux/mutex.h> 918c2ecf20Sopenharmony_ci#include <linux/of_device.h> 928c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 938c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 948c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Addresses to scan 988c2ecf20Sopenharmony_ci * Address is fully defined internally and cannot be changed except for 998c2ecf20Sopenharmony_ci * MAX6659, MAX6680 and MAX6681. 1008c2ecf20Sopenharmony_ci * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649, 1018c2ecf20Sopenharmony_ci * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c. 1028c2ecf20Sopenharmony_ci * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D 1038c2ecf20Sopenharmony_ci * have address 0x4d. 1048c2ecf20Sopenharmony_ci * MAX6647 has address 0x4e. 1058c2ecf20Sopenharmony_ci * MAX6659 can have address 0x4c, 0x4d or 0x4e. 1068c2ecf20Sopenharmony_ci * MAX6654, MAX6680, and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 1078c2ecf20Sopenharmony_ci * 0x2a, 0x2b, 0x4c, 0x4d or 0x4e. 1088c2ecf20Sopenharmony_ci * SA56004 can have address 0x48 through 0x4F. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 1128c2ecf20Sopenharmony_ci 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 1138c2ecf20Sopenharmony_ci 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cienum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, 1168c2ecf20Sopenharmony_ci max6646, w83l771, max6696, sa56004, g781, tmp451, tmp461, max6654 }; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * The LM90 registers 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define LM90_REG_R_MAN_ID 0xFE 1238c2ecf20Sopenharmony_ci#define LM90_REG_R_CHIP_ID 0xFF 1248c2ecf20Sopenharmony_ci#define LM90_REG_R_CONFIG1 0x03 1258c2ecf20Sopenharmony_ci#define LM90_REG_W_CONFIG1 0x09 1268c2ecf20Sopenharmony_ci#define LM90_REG_R_CONFIG2 0xBF 1278c2ecf20Sopenharmony_ci#define LM90_REG_W_CONFIG2 0xBF 1288c2ecf20Sopenharmony_ci#define LM90_REG_R_CONVRATE 0x04 1298c2ecf20Sopenharmony_ci#define LM90_REG_W_CONVRATE 0x0A 1308c2ecf20Sopenharmony_ci#define LM90_REG_R_STATUS 0x02 1318c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_TEMP 0x00 1328c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_HIGH 0x05 1338c2ecf20Sopenharmony_ci#define LM90_REG_W_LOCAL_HIGH 0x0B 1348c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_LOW 0x06 1358c2ecf20Sopenharmony_ci#define LM90_REG_W_LOCAL_LOW 0x0C 1368c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_CRIT 0x20 1378c2ecf20Sopenharmony_ci#define LM90_REG_W_LOCAL_CRIT 0x20 1388c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_TEMPH 0x01 1398c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_TEMPL 0x10 1408c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_OFFSH 0x11 1418c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_OFFSH 0x11 1428c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_OFFSL 0x12 1438c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_OFFSL 0x12 1448c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_HIGHH 0x07 1458c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_HIGHH 0x0D 1468c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_HIGHL 0x13 1478c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_HIGHL 0x13 1488c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_LOWH 0x08 1498c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_LOWH 0x0E 1508c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_LOWL 0x14 1518c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_LOWL 0x14 1528c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_CRIT 0x19 1538c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_CRIT 0x19 1548c2ecf20Sopenharmony_ci#define LM90_REG_R_TCRIT_HYST 0x21 1558c2ecf20Sopenharmony_ci#define LM90_REG_W_TCRIT_HYST 0x21 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* MAX6646/6647/6649/6654/6657/6658/6659/6695/6696 registers */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define MAX6657_REG_R_LOCAL_TEMPL 0x11 1608c2ecf20Sopenharmony_ci#define MAX6696_REG_R_STATUS2 0x12 1618c2ecf20Sopenharmony_ci#define MAX6659_REG_R_REMOTE_EMERG 0x16 1628c2ecf20Sopenharmony_ci#define MAX6659_REG_W_REMOTE_EMERG 0x16 1638c2ecf20Sopenharmony_ci#define MAX6659_REG_R_LOCAL_EMERG 0x17 1648c2ecf20Sopenharmony_ci#define MAX6659_REG_W_LOCAL_EMERG 0x17 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* SA56004 registers */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define SA56004_REG_R_LOCAL_TEMPL 0x22 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* TMP451/TMP461 registers */ 1738c2ecf20Sopenharmony_ci#define TMP451_REG_R_LOCAL_TEMPL 0x15 1748c2ecf20Sopenharmony_ci#define TMP451_REG_CONALERT 0x22 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define TMP461_REG_CHEN 0x16 1778c2ecf20Sopenharmony_ci#define TMP461_REG_DFC 0x24 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * Device flags 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci#define LM90_FLAG_ADT7461_EXT (1 << 0) /* ADT7461 extended mode */ 1838c2ecf20Sopenharmony_ci/* Device features */ 1848c2ecf20Sopenharmony_ci#define LM90_HAVE_OFFSET (1 << 1) /* temperature offset register */ 1858c2ecf20Sopenharmony_ci#define LM90_HAVE_REM_LIMIT_EXT (1 << 3) /* extended remote limit */ 1868c2ecf20Sopenharmony_ci#define LM90_HAVE_EMERGENCY (1 << 4) /* 3rd upper (emergency) limit */ 1878c2ecf20Sopenharmony_ci#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm */ 1888c2ecf20Sopenharmony_ci#define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */ 1898c2ecf20Sopenharmony_ci#define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */ 1908c2ecf20Sopenharmony_ci#define LM90_HAVE_EXTENDED_TEMP (1 << 8) /* extended temperature support*/ 1918c2ecf20Sopenharmony_ci#define LM90_PAUSE_FOR_CONFIG (1 << 9) /* Pause conversion for config */ 1928c2ecf20Sopenharmony_ci#define LM90_HAVE_CRIT (1 << 10)/* Chip supports CRIT/OVERT register */ 1938c2ecf20Sopenharmony_ci#define LM90_HAVE_CRIT_ALRM_SWP (1 << 11)/* critical alarm bits swapped */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* LM90 status */ 1968c2ecf20Sopenharmony_ci#define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */ 1978c2ecf20Sopenharmony_ci#define LM90_STATUS_RTHRM (1 << 1) /* remote THERM limit tripped */ 1988c2ecf20Sopenharmony_ci#define LM90_STATUS_ROPEN (1 << 2) /* remote is an open circuit */ 1998c2ecf20Sopenharmony_ci#define LM90_STATUS_RLOW (1 << 3) /* remote low temp limit tripped */ 2008c2ecf20Sopenharmony_ci#define LM90_STATUS_RHIGH (1 << 4) /* remote high temp limit tripped */ 2018c2ecf20Sopenharmony_ci#define LM90_STATUS_LLOW (1 << 5) /* local low temp limit tripped */ 2028c2ecf20Sopenharmony_ci#define LM90_STATUS_LHIGH (1 << 6) /* local high temp limit tripped */ 2038c2ecf20Sopenharmony_ci#define LM90_STATUS_BUSY (1 << 7) /* conversion is ongoing */ 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2THRM (1 << 1) /* remote2 THERM limit tripped */ 2068c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2OPEN (1 << 2) /* remote2 is an open circuit */ 2078c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2LOW (1 << 3) /* remote2 low temp limit tripped */ 2088c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2HIGH (1 << 4) /* remote2 high temp limit tripped */ 2098c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_ROT2 (1 << 5) /* remote emergency limit tripped */ 2108c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2OT2 (1 << 6) /* remote2 emergency limit tripped */ 2118c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_LOT2 (1 << 7) /* local emergency limit tripped */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * Driver data (common to all clients) 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm90_id[] = { 2188c2ecf20Sopenharmony_ci { "adm1032", adm1032 }, 2198c2ecf20Sopenharmony_ci { "adt7461", adt7461 }, 2208c2ecf20Sopenharmony_ci { "adt7461a", adt7461 }, 2218c2ecf20Sopenharmony_ci { "g781", g781 }, 2228c2ecf20Sopenharmony_ci { "lm90", lm90 }, 2238c2ecf20Sopenharmony_ci { "lm86", lm86 }, 2248c2ecf20Sopenharmony_ci { "lm89", lm86 }, 2258c2ecf20Sopenharmony_ci { "lm99", lm99 }, 2268c2ecf20Sopenharmony_ci { "max6646", max6646 }, 2278c2ecf20Sopenharmony_ci { "max6647", max6646 }, 2288c2ecf20Sopenharmony_ci { "max6649", max6646 }, 2298c2ecf20Sopenharmony_ci { "max6654", max6654 }, 2308c2ecf20Sopenharmony_ci { "max6657", max6657 }, 2318c2ecf20Sopenharmony_ci { "max6658", max6657 }, 2328c2ecf20Sopenharmony_ci { "max6659", max6659 }, 2338c2ecf20Sopenharmony_ci { "max6680", max6680 }, 2348c2ecf20Sopenharmony_ci { "max6681", max6680 }, 2358c2ecf20Sopenharmony_ci { "max6695", max6696 }, 2368c2ecf20Sopenharmony_ci { "max6696", max6696 }, 2378c2ecf20Sopenharmony_ci { "nct1008", adt7461 }, 2388c2ecf20Sopenharmony_ci { "w83l771", w83l771 }, 2398c2ecf20Sopenharmony_ci { "sa56004", sa56004 }, 2408c2ecf20Sopenharmony_ci { "tmp451", tmp451 }, 2418c2ecf20Sopenharmony_ci { "tmp461", tmp461 }, 2428c2ecf20Sopenharmony_ci { } 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm90_id); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused lm90_of_match[] = { 2478c2ecf20Sopenharmony_ci { 2488c2ecf20Sopenharmony_ci .compatible = "adi,adm1032", 2498c2ecf20Sopenharmony_ci .data = (void *)adm1032 2508c2ecf20Sopenharmony_ci }, 2518c2ecf20Sopenharmony_ci { 2528c2ecf20Sopenharmony_ci .compatible = "adi,adt7461", 2538c2ecf20Sopenharmony_ci .data = (void *)adt7461 2548c2ecf20Sopenharmony_ci }, 2558c2ecf20Sopenharmony_ci { 2568c2ecf20Sopenharmony_ci .compatible = "adi,adt7461a", 2578c2ecf20Sopenharmony_ci .data = (void *)adt7461 2588c2ecf20Sopenharmony_ci }, 2598c2ecf20Sopenharmony_ci { 2608c2ecf20Sopenharmony_ci .compatible = "gmt,g781", 2618c2ecf20Sopenharmony_ci .data = (void *)g781 2628c2ecf20Sopenharmony_ci }, 2638c2ecf20Sopenharmony_ci { 2648c2ecf20Sopenharmony_ci .compatible = "national,lm90", 2658c2ecf20Sopenharmony_ci .data = (void *)lm90 2668c2ecf20Sopenharmony_ci }, 2678c2ecf20Sopenharmony_ci { 2688c2ecf20Sopenharmony_ci .compatible = "national,lm86", 2698c2ecf20Sopenharmony_ci .data = (void *)lm86 2708c2ecf20Sopenharmony_ci }, 2718c2ecf20Sopenharmony_ci { 2728c2ecf20Sopenharmony_ci .compatible = "national,lm89", 2738c2ecf20Sopenharmony_ci .data = (void *)lm86 2748c2ecf20Sopenharmony_ci }, 2758c2ecf20Sopenharmony_ci { 2768c2ecf20Sopenharmony_ci .compatible = "national,lm99", 2778c2ecf20Sopenharmony_ci .data = (void *)lm99 2788c2ecf20Sopenharmony_ci }, 2798c2ecf20Sopenharmony_ci { 2808c2ecf20Sopenharmony_ci .compatible = "dallas,max6646", 2818c2ecf20Sopenharmony_ci .data = (void *)max6646 2828c2ecf20Sopenharmony_ci }, 2838c2ecf20Sopenharmony_ci { 2848c2ecf20Sopenharmony_ci .compatible = "dallas,max6647", 2858c2ecf20Sopenharmony_ci .data = (void *)max6646 2868c2ecf20Sopenharmony_ci }, 2878c2ecf20Sopenharmony_ci { 2888c2ecf20Sopenharmony_ci .compatible = "dallas,max6649", 2898c2ecf20Sopenharmony_ci .data = (void *)max6646 2908c2ecf20Sopenharmony_ci }, 2918c2ecf20Sopenharmony_ci { 2928c2ecf20Sopenharmony_ci .compatible = "dallas,max6654", 2938c2ecf20Sopenharmony_ci .data = (void *)max6654 2948c2ecf20Sopenharmony_ci }, 2958c2ecf20Sopenharmony_ci { 2968c2ecf20Sopenharmony_ci .compatible = "dallas,max6657", 2978c2ecf20Sopenharmony_ci .data = (void *)max6657 2988c2ecf20Sopenharmony_ci }, 2998c2ecf20Sopenharmony_ci { 3008c2ecf20Sopenharmony_ci .compatible = "dallas,max6658", 3018c2ecf20Sopenharmony_ci .data = (void *)max6657 3028c2ecf20Sopenharmony_ci }, 3038c2ecf20Sopenharmony_ci { 3048c2ecf20Sopenharmony_ci .compatible = "dallas,max6659", 3058c2ecf20Sopenharmony_ci .data = (void *)max6659 3068c2ecf20Sopenharmony_ci }, 3078c2ecf20Sopenharmony_ci { 3088c2ecf20Sopenharmony_ci .compatible = "dallas,max6680", 3098c2ecf20Sopenharmony_ci .data = (void *)max6680 3108c2ecf20Sopenharmony_ci }, 3118c2ecf20Sopenharmony_ci { 3128c2ecf20Sopenharmony_ci .compatible = "dallas,max6681", 3138c2ecf20Sopenharmony_ci .data = (void *)max6680 3148c2ecf20Sopenharmony_ci }, 3158c2ecf20Sopenharmony_ci { 3168c2ecf20Sopenharmony_ci .compatible = "dallas,max6695", 3178c2ecf20Sopenharmony_ci .data = (void *)max6696 3188c2ecf20Sopenharmony_ci }, 3198c2ecf20Sopenharmony_ci { 3208c2ecf20Sopenharmony_ci .compatible = "dallas,max6696", 3218c2ecf20Sopenharmony_ci .data = (void *)max6696 3228c2ecf20Sopenharmony_ci }, 3238c2ecf20Sopenharmony_ci { 3248c2ecf20Sopenharmony_ci .compatible = "onnn,nct1008", 3258c2ecf20Sopenharmony_ci .data = (void *)adt7461 3268c2ecf20Sopenharmony_ci }, 3278c2ecf20Sopenharmony_ci { 3288c2ecf20Sopenharmony_ci .compatible = "winbond,w83l771", 3298c2ecf20Sopenharmony_ci .data = (void *)w83l771 3308c2ecf20Sopenharmony_ci }, 3318c2ecf20Sopenharmony_ci { 3328c2ecf20Sopenharmony_ci .compatible = "nxp,sa56004", 3338c2ecf20Sopenharmony_ci .data = (void *)sa56004 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci { 3368c2ecf20Sopenharmony_ci .compatible = "ti,tmp451", 3378c2ecf20Sopenharmony_ci .data = (void *)tmp451 3388c2ecf20Sopenharmony_ci }, 3398c2ecf20Sopenharmony_ci { 3408c2ecf20Sopenharmony_ci .compatible = "ti,tmp461", 3418c2ecf20Sopenharmony_ci .data = (void *)tmp461 3428c2ecf20Sopenharmony_ci }, 3438c2ecf20Sopenharmony_ci { }, 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lm90_of_match); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* 3488c2ecf20Sopenharmony_ci * chip type specific parameters 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_cistruct lm90_params { 3518c2ecf20Sopenharmony_ci u32 flags; /* Capabilities */ 3528c2ecf20Sopenharmony_ci u16 alert_alarms; /* Which alarm bits trigger ALERT# */ 3538c2ecf20Sopenharmony_ci /* Upper 8 bits for max6695/96 */ 3548c2ecf20Sopenharmony_ci u8 max_convrate; /* Maximum conversion rate register value */ 3558c2ecf20Sopenharmony_ci u8 reg_local_ext; /* Extended local temp register (optional) */ 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic const struct lm90_params lm90_params[] = { 3598c2ecf20Sopenharmony_ci [adm1032] = { 3608c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 3618c2ecf20Sopenharmony_ci | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT, 3628c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 3638c2ecf20Sopenharmony_ci .max_convrate = 10, 3648c2ecf20Sopenharmony_ci }, 3658c2ecf20Sopenharmony_ci [adt7461] = { 3668c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 3678c2ecf20Sopenharmony_ci | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP 3688c2ecf20Sopenharmony_ci | LM90_HAVE_CRIT, 3698c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 3708c2ecf20Sopenharmony_ci .max_convrate = 10, 3718c2ecf20Sopenharmony_ci }, 3728c2ecf20Sopenharmony_ci [g781] = { 3738c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 3748c2ecf20Sopenharmony_ci | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT, 3758c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 3768c2ecf20Sopenharmony_ci .max_convrate = 7, 3778c2ecf20Sopenharmony_ci }, 3788c2ecf20Sopenharmony_ci [lm86] = { 3798c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 3808c2ecf20Sopenharmony_ci | LM90_HAVE_CRIT, 3818c2ecf20Sopenharmony_ci .alert_alarms = 0x7b, 3828c2ecf20Sopenharmony_ci .max_convrate = 9, 3838c2ecf20Sopenharmony_ci }, 3848c2ecf20Sopenharmony_ci [lm90] = { 3858c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 3868c2ecf20Sopenharmony_ci | LM90_HAVE_CRIT, 3878c2ecf20Sopenharmony_ci .alert_alarms = 0x7b, 3888c2ecf20Sopenharmony_ci .max_convrate = 9, 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci [lm99] = { 3918c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 3928c2ecf20Sopenharmony_ci | LM90_HAVE_CRIT, 3938c2ecf20Sopenharmony_ci .alert_alarms = 0x7b, 3948c2ecf20Sopenharmony_ci .max_convrate = 9, 3958c2ecf20Sopenharmony_ci }, 3968c2ecf20Sopenharmony_ci [max6646] = { 3978c2ecf20Sopenharmony_ci .flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT, 3988c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 3998c2ecf20Sopenharmony_ci .max_convrate = 6, 4008c2ecf20Sopenharmony_ci .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, 4018c2ecf20Sopenharmony_ci }, 4028c2ecf20Sopenharmony_ci [max6654] = { 4038c2ecf20Sopenharmony_ci .flags = LM90_HAVE_BROKEN_ALERT, 4048c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4058c2ecf20Sopenharmony_ci .max_convrate = 7, 4068c2ecf20Sopenharmony_ci .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci [max6657] = { 4098c2ecf20Sopenharmony_ci .flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT, 4108c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4118c2ecf20Sopenharmony_ci .max_convrate = 8, 4128c2ecf20Sopenharmony_ci .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci [max6659] = { 4158c2ecf20Sopenharmony_ci .flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT, 4168c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4178c2ecf20Sopenharmony_ci .max_convrate = 8, 4188c2ecf20Sopenharmony_ci .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, 4198c2ecf20Sopenharmony_ci }, 4208c2ecf20Sopenharmony_ci [max6680] = { 4218c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT 4228c2ecf20Sopenharmony_ci | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT, 4238c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4248c2ecf20Sopenharmony_ci .max_convrate = 7, 4258c2ecf20Sopenharmony_ci }, 4268c2ecf20Sopenharmony_ci [max6696] = { 4278c2ecf20Sopenharmony_ci .flags = LM90_HAVE_EMERGENCY 4288c2ecf20Sopenharmony_ci | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT, 4298c2ecf20Sopenharmony_ci .alert_alarms = 0x1c7c, 4308c2ecf20Sopenharmony_ci .max_convrate = 6, 4318c2ecf20Sopenharmony_ci .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, 4328c2ecf20Sopenharmony_ci }, 4338c2ecf20Sopenharmony_ci [w83l771] = { 4348c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT, 4358c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4368c2ecf20Sopenharmony_ci .max_convrate = 8, 4378c2ecf20Sopenharmony_ci }, 4388c2ecf20Sopenharmony_ci [sa56004] = { 4398c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT, 4408c2ecf20Sopenharmony_ci .alert_alarms = 0x7b, 4418c2ecf20Sopenharmony_ci .max_convrate = 9, 4428c2ecf20Sopenharmony_ci .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL, 4438c2ecf20Sopenharmony_ci }, 4448c2ecf20Sopenharmony_ci [tmp451] = { 4458c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 4468c2ecf20Sopenharmony_ci | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT, 4478c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4488c2ecf20Sopenharmony_ci .max_convrate = 9, 4498c2ecf20Sopenharmony_ci .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL, 4508c2ecf20Sopenharmony_ci }, 4518c2ecf20Sopenharmony_ci [tmp461] = { 4528c2ecf20Sopenharmony_ci .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT 4538c2ecf20Sopenharmony_ci | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT, 4548c2ecf20Sopenharmony_ci .alert_alarms = 0x7c, 4558c2ecf20Sopenharmony_ci .max_convrate = 9, 4568c2ecf20Sopenharmony_ci .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL, 4578c2ecf20Sopenharmony_ci }, 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/* 4618c2ecf20Sopenharmony_ci * TEMP8 register index 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_cienum lm90_temp8_reg_index { 4648c2ecf20Sopenharmony_ci LOCAL_LOW = 0, 4658c2ecf20Sopenharmony_ci LOCAL_HIGH, 4668c2ecf20Sopenharmony_ci LOCAL_CRIT, 4678c2ecf20Sopenharmony_ci REMOTE_CRIT, 4688c2ecf20Sopenharmony_ci LOCAL_EMERG, /* max6659 and max6695/96 */ 4698c2ecf20Sopenharmony_ci REMOTE_EMERG, /* max6659 and max6695/96 */ 4708c2ecf20Sopenharmony_ci REMOTE2_CRIT, /* max6695/96 only */ 4718c2ecf20Sopenharmony_ci REMOTE2_EMERG, /* max6695/96 only */ 4728c2ecf20Sopenharmony_ci TEMP8_REG_NUM 4738c2ecf20Sopenharmony_ci}; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* 4768c2ecf20Sopenharmony_ci * TEMP11 register index 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_cienum lm90_temp11_reg_index { 4798c2ecf20Sopenharmony_ci REMOTE_TEMP = 0, 4808c2ecf20Sopenharmony_ci REMOTE_LOW, 4818c2ecf20Sopenharmony_ci REMOTE_HIGH, 4828c2ecf20Sopenharmony_ci REMOTE_OFFSET, /* except max6646, max6657/58/59, and max6695/96 */ 4838c2ecf20Sopenharmony_ci LOCAL_TEMP, 4848c2ecf20Sopenharmony_ci REMOTE2_TEMP, /* max6695/96 only */ 4858c2ecf20Sopenharmony_ci REMOTE2_LOW, /* max6695/96 only */ 4868c2ecf20Sopenharmony_ci REMOTE2_HIGH, /* max6695/96 only */ 4878c2ecf20Sopenharmony_ci TEMP11_REG_NUM 4888c2ecf20Sopenharmony_ci}; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* 4918c2ecf20Sopenharmony_ci * Client data (each client gets its own) 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistruct lm90_data { 4958c2ecf20Sopenharmony_ci struct i2c_client *client; 4968c2ecf20Sopenharmony_ci u32 channel_config[4]; 4978c2ecf20Sopenharmony_ci struct hwmon_channel_info temp_info; 4988c2ecf20Sopenharmony_ci const struct hwmon_channel_info *info[3]; 4998c2ecf20Sopenharmony_ci struct hwmon_chip_info chip; 5008c2ecf20Sopenharmony_ci struct mutex update_lock; 5018c2ecf20Sopenharmony_ci bool valid; /* true if register values are valid */ 5028c2ecf20Sopenharmony_ci unsigned long last_updated; /* in jiffies */ 5038c2ecf20Sopenharmony_ci int kind; 5048c2ecf20Sopenharmony_ci u32 flags; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci unsigned int update_interval; /* in milliseconds */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci u8 config; /* Current configuration register value */ 5098c2ecf20Sopenharmony_ci u8 config_orig; /* Original configuration register value */ 5108c2ecf20Sopenharmony_ci u8 convrate_orig; /* Original conversion rate register value */ 5118c2ecf20Sopenharmony_ci u16 alert_alarms; /* Which alarm bits trigger ALERT# */ 5128c2ecf20Sopenharmony_ci /* Upper 8 bits for max6695/96 */ 5138c2ecf20Sopenharmony_ci u8 max_convrate; /* Maximum conversion rate */ 5148c2ecf20Sopenharmony_ci u8 reg_local_ext; /* local extension register offset */ 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* registers values */ 5178c2ecf20Sopenharmony_ci s8 temp8[TEMP8_REG_NUM]; 5188c2ecf20Sopenharmony_ci s16 temp11[TEMP11_REG_NUM]; 5198c2ecf20Sopenharmony_ci u8 temp_hyst; 5208c2ecf20Sopenharmony_ci u16 alarms; /* bitvector (upper 8 bits for max6695/96) */ 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* 5248c2ecf20Sopenharmony_ci * Support functions 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* 5288c2ecf20Sopenharmony_ci * The ADM1032 supports PEC but not on write byte transactions, so we need 5298c2ecf20Sopenharmony_ci * to explicitly ask for a transaction without PEC. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_cistatic inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci return i2c_smbus_xfer(client->adapter, client->addr, 5348c2ecf20Sopenharmony_ci client->flags & ~I2C_CLIENT_PEC, 5358c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/* 5398c2ecf20Sopenharmony_ci * It is assumed that client->update_lock is held (unless we are in 5408c2ecf20Sopenharmony_ci * detection or initialization steps). This matters when PEC is enabled, 5418c2ecf20Sopenharmony_ci * because we don't want the address pointer to change between the write 5428c2ecf20Sopenharmony_ci * byte and the read byte transactions. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic int lm90_read_reg(struct i2c_client *client, u8 reg) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int err; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (client->flags & I2C_CLIENT_PEC) { 5498c2ecf20Sopenharmony_ci err = adm1032_write_byte(client, reg); 5508c2ecf20Sopenharmony_ci if (err >= 0) 5518c2ecf20Sopenharmony_ci err = i2c_smbus_read_byte(client); 5528c2ecf20Sopenharmony_ci } else 5538c2ecf20Sopenharmony_ci err = i2c_smbus_read_byte_data(client, reg); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return err; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic int lm90_read16(struct i2c_client *client, u8 regh, u8 regl) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci int oldh, newh, l; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* 5638c2ecf20Sopenharmony_ci * There is a trick here. We have to read two registers to have the 5648c2ecf20Sopenharmony_ci * sensor temperature, but we have to beware a conversion could occur 5658c2ecf20Sopenharmony_ci * between the readings. The datasheet says we should either use 5668c2ecf20Sopenharmony_ci * the one-shot conversion register, which we don't want to do 5678c2ecf20Sopenharmony_ci * (disables hardware monitoring) or monitor the busy bit, which is 5688c2ecf20Sopenharmony_ci * impossible (we can't read the values and monitor that bit at the 5698c2ecf20Sopenharmony_ci * exact same time). So the solution used here is to read the high 5708c2ecf20Sopenharmony_ci * byte once, then the low byte, then the high byte again. If the new 5718c2ecf20Sopenharmony_ci * high byte matches the old one, then we have a valid reading. Else 5728c2ecf20Sopenharmony_ci * we have to read the low byte again, and now we believe we have a 5738c2ecf20Sopenharmony_ci * correct reading. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci oldh = lm90_read_reg(client, regh); 5768c2ecf20Sopenharmony_ci if (oldh < 0) 5778c2ecf20Sopenharmony_ci return oldh; 5788c2ecf20Sopenharmony_ci l = lm90_read_reg(client, regl); 5798c2ecf20Sopenharmony_ci if (l < 0) 5808c2ecf20Sopenharmony_ci return l; 5818c2ecf20Sopenharmony_ci newh = lm90_read_reg(client, regh); 5828c2ecf20Sopenharmony_ci if (newh < 0) 5838c2ecf20Sopenharmony_ci return newh; 5848c2ecf20Sopenharmony_ci if (oldh != newh) { 5858c2ecf20Sopenharmony_ci l = lm90_read_reg(client, regl); 5868c2ecf20Sopenharmony_ci if (l < 0) 5878c2ecf20Sopenharmony_ci return l; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci return (newh << 8) | l; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int lm90_update_confreg(struct lm90_data *data, u8 config) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci if (data->config != config) { 5958c2ecf20Sopenharmony_ci int err; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(data->client, 5988c2ecf20Sopenharmony_ci LM90_REG_W_CONFIG1, 5998c2ecf20Sopenharmony_ci config); 6008c2ecf20Sopenharmony_ci if (err) 6018c2ecf20Sopenharmony_ci return err; 6028c2ecf20Sopenharmony_ci data->config = config; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/* 6088c2ecf20Sopenharmony_ci * client->update_lock must be held when calling this function (unless we are 6098c2ecf20Sopenharmony_ci * in detection or initialization steps), and while a remote channel other 6108c2ecf20Sopenharmony_ci * than channel 0 is selected. Also, calling code must make sure to re-select 6118c2ecf20Sopenharmony_ci * external channel 0 before releasing the lock. This is necessary because 6128c2ecf20Sopenharmony_ci * various registers have different meanings as a result of selecting a 6138c2ecf20Sopenharmony_ci * non-default remote channel. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_cistatic int lm90_select_remote_channel(struct lm90_data *data, int channel) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci int err = 0; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (data->kind == max6696) { 6208c2ecf20Sopenharmony_ci u8 config = data->config & ~0x08; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (channel) 6238c2ecf20Sopenharmony_ci config |= 0x08; 6248c2ecf20Sopenharmony_ci err = lm90_update_confreg(data, config); 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci return err; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int lm90_write_convrate(struct lm90_data *data, int val) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci u8 config = data->config; 6328c2ecf20Sopenharmony_ci int err; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* Save config and pause conversion */ 6358c2ecf20Sopenharmony_ci if (data->flags & LM90_PAUSE_FOR_CONFIG) { 6368c2ecf20Sopenharmony_ci err = lm90_update_confreg(data, config | 0x40); 6378c2ecf20Sopenharmony_ci if (err < 0) 6388c2ecf20Sopenharmony_ci return err; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Set conv rate */ 6428c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Revert change to config */ 6458c2ecf20Sopenharmony_ci lm90_update_confreg(data, config); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return err; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci/* 6518c2ecf20Sopenharmony_ci * Set conversion rate. 6528c2ecf20Sopenharmony_ci * client->update_lock must be held when calling this function (unless we are 6538c2ecf20Sopenharmony_ci * in detection or initialization steps). 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_cistatic int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data, 6568c2ecf20Sopenharmony_ci unsigned int interval) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci unsigned int update_interval; 6598c2ecf20Sopenharmony_ci int i, err; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Shift calculations to avoid rounding errors */ 6628c2ecf20Sopenharmony_ci interval <<= 6; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* find the nearest update rate */ 6658c2ecf20Sopenharmony_ci for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6; 6668c2ecf20Sopenharmony_ci i < data->max_convrate; i++, update_interval >>= 1) 6678c2ecf20Sopenharmony_ci if (interval >= update_interval * 3 / 4) 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci err = lm90_write_convrate(data, i); 6718c2ecf20Sopenharmony_ci data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64); 6728c2ecf20Sopenharmony_ci return err; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int lm90_update_limits(struct device *dev) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct lm90_data *data = dev_get_drvdata(dev); 6788c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 6798c2ecf20Sopenharmony_ci int val; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_CRIT) { 6828c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT); 6838c2ecf20Sopenharmony_ci if (val < 0) 6848c2ecf20Sopenharmony_ci return val; 6858c2ecf20Sopenharmony_ci data->temp8[LOCAL_CRIT] = val; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); 6888c2ecf20Sopenharmony_ci if (val < 0) 6898c2ecf20Sopenharmony_ci return val; 6908c2ecf20Sopenharmony_ci data->temp8[REMOTE_CRIT] = val; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST); 6938c2ecf20Sopenharmony_ci if (val < 0) 6948c2ecf20Sopenharmony_ci return val; 6958c2ecf20Sopenharmony_ci data->temp_hyst = val; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); 6998c2ecf20Sopenharmony_ci if (val < 0) 7008c2ecf20Sopenharmony_ci return val; 7018c2ecf20Sopenharmony_ci data->temp11[REMOTE_LOW] = val << 8; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { 7048c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL); 7058c2ecf20Sopenharmony_ci if (val < 0) 7068c2ecf20Sopenharmony_ci return val; 7078c2ecf20Sopenharmony_ci data->temp11[REMOTE_LOW] |= val; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); 7118c2ecf20Sopenharmony_ci if (val < 0) 7128c2ecf20Sopenharmony_ci return val; 7138c2ecf20Sopenharmony_ci data->temp11[REMOTE_HIGH] = val << 8; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { 7168c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL); 7178c2ecf20Sopenharmony_ci if (val < 0) 7188c2ecf20Sopenharmony_ci return val; 7198c2ecf20Sopenharmony_ci data->temp11[REMOTE_HIGH] |= val; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_OFFSET) { 7238c2ecf20Sopenharmony_ci val = lm90_read16(client, LM90_REG_R_REMOTE_OFFSH, 7248c2ecf20Sopenharmony_ci LM90_REG_R_REMOTE_OFFSL); 7258c2ecf20Sopenharmony_ci if (val < 0) 7268c2ecf20Sopenharmony_ci return val; 7278c2ecf20Sopenharmony_ci data->temp11[REMOTE_OFFSET] = val; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EMERGENCY) { 7318c2ecf20Sopenharmony_ci val = lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG); 7328c2ecf20Sopenharmony_ci if (val < 0) 7338c2ecf20Sopenharmony_ci return val; 7348c2ecf20Sopenharmony_ci data->temp8[LOCAL_EMERG] = val; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); 7378c2ecf20Sopenharmony_ci if (val < 0) 7388c2ecf20Sopenharmony_ci return val; 7398c2ecf20Sopenharmony_ci data->temp8[REMOTE_EMERG] = val; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (data->kind == max6696) { 7438c2ecf20Sopenharmony_ci val = lm90_select_remote_channel(data, 1); 7448c2ecf20Sopenharmony_ci if (val < 0) 7458c2ecf20Sopenharmony_ci return val; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); 7488c2ecf20Sopenharmony_ci if (val < 0) 7498c2ecf20Sopenharmony_ci return val; 7508c2ecf20Sopenharmony_ci data->temp8[REMOTE2_CRIT] = val; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); 7538c2ecf20Sopenharmony_ci if (val < 0) 7548c2ecf20Sopenharmony_ci return val; 7558c2ecf20Sopenharmony_ci data->temp8[REMOTE2_EMERG] = val; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); 7588c2ecf20Sopenharmony_ci if (val < 0) 7598c2ecf20Sopenharmony_ci return val; 7608c2ecf20Sopenharmony_ci data->temp11[REMOTE2_LOW] = val << 8; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); 7638c2ecf20Sopenharmony_ci if (val < 0) 7648c2ecf20Sopenharmony_ci return val; 7658c2ecf20Sopenharmony_ci data->temp11[REMOTE2_HIGH] = val << 8; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, 0); 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic int lm90_update_device(struct device *dev) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct lm90_data *data = dev_get_drvdata(dev); 7768c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 7778c2ecf20Sopenharmony_ci unsigned long next_update; 7788c2ecf20Sopenharmony_ci int val; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!data->valid) { 7818c2ecf20Sopenharmony_ci val = lm90_update_limits(dev); 7828c2ecf20Sopenharmony_ci if (val < 0) 7838c2ecf20Sopenharmony_ci return val; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci next_update = data->last_updated + 7878c2ecf20Sopenharmony_ci msecs_to_jiffies(data->update_interval); 7888c2ecf20Sopenharmony_ci if (time_after(jiffies, next_update) || !data->valid) { 7898c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Updating lm90 data.\n"); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci data->valid = false; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_LOCAL_LOW); 7948c2ecf20Sopenharmony_ci if (val < 0) 7958c2ecf20Sopenharmony_ci return val; 7968c2ecf20Sopenharmony_ci data->temp8[LOCAL_LOW] = val; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH); 7998c2ecf20Sopenharmony_ci if (val < 0) 8008c2ecf20Sopenharmony_ci return val; 8018c2ecf20Sopenharmony_ci data->temp8[LOCAL_HIGH] = val; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (data->reg_local_ext) { 8048c2ecf20Sopenharmony_ci val = lm90_read16(client, LM90_REG_R_LOCAL_TEMP, 8058c2ecf20Sopenharmony_ci data->reg_local_ext); 8068c2ecf20Sopenharmony_ci if (val < 0) 8078c2ecf20Sopenharmony_ci return val; 8088c2ecf20Sopenharmony_ci data->temp11[LOCAL_TEMP] = val; 8098c2ecf20Sopenharmony_ci } else { 8108c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP); 8118c2ecf20Sopenharmony_ci if (val < 0) 8128c2ecf20Sopenharmony_ci return val; 8138c2ecf20Sopenharmony_ci data->temp11[LOCAL_TEMP] = val << 8; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, 8168c2ecf20Sopenharmony_ci LM90_REG_R_REMOTE_TEMPL); 8178c2ecf20Sopenharmony_ci if (val < 0) 8188c2ecf20Sopenharmony_ci return val; 8198c2ecf20Sopenharmony_ci data->temp11[REMOTE_TEMP] = val; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci val = lm90_read_reg(client, LM90_REG_R_STATUS); 8228c2ecf20Sopenharmony_ci if (val < 0) 8238c2ecf20Sopenharmony_ci return val; 8248c2ecf20Sopenharmony_ci data->alarms = val & ~LM90_STATUS_BUSY; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (data->kind == max6696) { 8278c2ecf20Sopenharmony_ci val = lm90_select_remote_channel(data, 1); 8288c2ecf20Sopenharmony_ci if (val < 0) 8298c2ecf20Sopenharmony_ci return val; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, 8328c2ecf20Sopenharmony_ci LM90_REG_R_REMOTE_TEMPL); 8338c2ecf20Sopenharmony_ci if (val < 0) { 8348c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, 0); 8358c2ecf20Sopenharmony_ci return val; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci data->temp11[REMOTE2_TEMP] = val; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, 0); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci val = lm90_read_reg(client, MAX6696_REG_R_STATUS2); 8428c2ecf20Sopenharmony_ci if (val < 0) 8438c2ecf20Sopenharmony_ci return val; 8448c2ecf20Sopenharmony_ci data->alarms |= val << 8; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* 8488c2ecf20Sopenharmony_ci * Re-enable ALERT# output if it was originally enabled and 8498c2ecf20Sopenharmony_ci * relevant alarms are all clear 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci if (!(data->config_orig & 0x80) && 8528c2ecf20Sopenharmony_ci !(data->alarms & data->alert_alarms)) { 8538c2ecf20Sopenharmony_ci if (data->config & 0x80) { 8548c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Re-enabling ALERT#\n"); 8558c2ecf20Sopenharmony_ci lm90_update_confreg(data, data->config & ~0x80); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci data->last_updated = jiffies; 8608c2ecf20Sopenharmony_ci data->valid = true; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci return 0; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci/* 8678c2ecf20Sopenharmony_ci * Conversions 8688c2ecf20Sopenharmony_ci * For local temperatures and limits, critical limits and the hysteresis 8698c2ecf20Sopenharmony_ci * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. 8708c2ecf20Sopenharmony_ci * For remote temperatures and limits, it uses signed 11-bit values with 8718c2ecf20Sopenharmony_ci * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. Some 8728c2ecf20Sopenharmony_ci * Maxim chips use unsigned values. 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic inline int temp_from_s8(s8 val) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci return val * 1000; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic inline int temp_from_u8(u8 val) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci return val * 1000; 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic inline int temp_from_s16(s16 val) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci return val / 32 * 125; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic inline int temp_from_u16(u16 val) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci return val / 32 * 125; 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic s8 temp_to_s8(long val) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci if (val <= -128000) 8988c2ecf20Sopenharmony_ci return -128; 8998c2ecf20Sopenharmony_ci if (val >= 127000) 9008c2ecf20Sopenharmony_ci return 127; 9018c2ecf20Sopenharmony_ci if (val < 0) 9028c2ecf20Sopenharmony_ci return (val - 500) / 1000; 9038c2ecf20Sopenharmony_ci return (val + 500) / 1000; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic u8 temp_to_u8(long val) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci if (val <= 0) 9098c2ecf20Sopenharmony_ci return 0; 9108c2ecf20Sopenharmony_ci if (val >= 255000) 9118c2ecf20Sopenharmony_ci return 255; 9128c2ecf20Sopenharmony_ci return (val + 500) / 1000; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic s16 temp_to_s16(long val) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci if (val <= -128000) 9188c2ecf20Sopenharmony_ci return 0x8000; 9198c2ecf20Sopenharmony_ci if (val >= 127875) 9208c2ecf20Sopenharmony_ci return 0x7FE0; 9218c2ecf20Sopenharmony_ci if (val < 0) 9228c2ecf20Sopenharmony_ci return (val - 62) / 125 * 32; 9238c2ecf20Sopenharmony_ci return (val + 62) / 125 * 32; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic u8 hyst_to_reg(long val) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci if (val <= 0) 9298c2ecf20Sopenharmony_ci return 0; 9308c2ecf20Sopenharmony_ci if (val >= 30500) 9318c2ecf20Sopenharmony_ci return 31; 9328c2ecf20Sopenharmony_ci return (val + 500) / 1000; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci/* 9368c2ecf20Sopenharmony_ci * ADT7461 in compatibility mode is almost identical to LM90 except that 9378c2ecf20Sopenharmony_ci * attempts to write values that are outside the range 0 < temp < 127 are 9388c2ecf20Sopenharmony_ci * treated as the boundary value. 9398c2ecf20Sopenharmony_ci * 9408c2ecf20Sopenharmony_ci * ADT7461 in "extended mode" operation uses unsigned integers offset by 9418c2ecf20Sopenharmony_ci * 64 (e.g., 0 -> -64 degC). The range is restricted to -64..191 degC. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_cistatic inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci if (data->flags & LM90_FLAG_ADT7461_EXT) 9468c2ecf20Sopenharmony_ci return (val - 64) * 1000; 9478c2ecf20Sopenharmony_ci return temp_from_s8(val); 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci if (data->flags & LM90_FLAG_ADT7461_EXT) 9538c2ecf20Sopenharmony_ci return (val - 0x4000) / 64 * 250; 9548c2ecf20Sopenharmony_ci return temp_from_s16(val); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic u8 temp_to_u8_adt7461(struct lm90_data *data, long val) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci if (data->flags & LM90_FLAG_ADT7461_EXT) { 9608c2ecf20Sopenharmony_ci if (val <= -64000) 9618c2ecf20Sopenharmony_ci return 0; 9628c2ecf20Sopenharmony_ci if (val >= 191000) 9638c2ecf20Sopenharmony_ci return 0xFF; 9648c2ecf20Sopenharmony_ci return (val + 500 + 64000) / 1000; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci if (val <= 0) 9678c2ecf20Sopenharmony_ci return 0; 9688c2ecf20Sopenharmony_ci if (val >= 127000) 9698c2ecf20Sopenharmony_ci return 127; 9708c2ecf20Sopenharmony_ci return (val + 500) / 1000; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic u16 temp_to_u16_adt7461(struct lm90_data *data, long val) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci if (data->flags & LM90_FLAG_ADT7461_EXT) { 9768c2ecf20Sopenharmony_ci if (val <= -64000) 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci if (val >= 191750) 9798c2ecf20Sopenharmony_ci return 0xFFC0; 9808c2ecf20Sopenharmony_ci return (val + 64000 + 125) / 250 * 64; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci if (val <= 0) 9838c2ecf20Sopenharmony_ci return 0; 9848c2ecf20Sopenharmony_ci if (val >= 127750) 9858c2ecf20Sopenharmony_ci return 0x7FC0; 9868c2ecf20Sopenharmony_ci return (val + 125) / 250 * 64; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/* pec used for ADM1032 only */ 9908c2ecf20Sopenharmony_cistatic ssize_t pec_show(struct device *dev, struct device_attribute *dummy, 9918c2ecf20Sopenharmony_ci char *buf) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic ssize_t pec_store(struct device *dev, struct device_attribute *dummy, 9998c2ecf20Sopenharmony_ci const char *buf, size_t count) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 10028c2ecf20Sopenharmony_ci long val; 10038c2ecf20Sopenharmony_ci int err; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 10068c2ecf20Sopenharmony_ci if (err < 0) 10078c2ecf20Sopenharmony_ci return err; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci switch (val) { 10108c2ecf20Sopenharmony_ci case 0: 10118c2ecf20Sopenharmony_ci client->flags &= ~I2C_CLIENT_PEC; 10128c2ecf20Sopenharmony_ci break; 10138c2ecf20Sopenharmony_ci case 1: 10148c2ecf20Sopenharmony_ci client->flags |= I2C_CLIENT_PEC; 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci default: 10178c2ecf20Sopenharmony_ci return -EINVAL; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return count; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(pec); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic int lm90_get_temp11(struct lm90_data *data, int index) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci s16 temp11 = data->temp11[index]; 10288c2ecf20Sopenharmony_ci int temp; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) 10318c2ecf20Sopenharmony_ci temp = temp_from_u16_adt7461(data, temp11); 10328c2ecf20Sopenharmony_ci else if (data->kind == max6646) 10338c2ecf20Sopenharmony_ci temp = temp_from_u16(temp11); 10348c2ecf20Sopenharmony_ci else 10358c2ecf20Sopenharmony_ci temp = temp_from_s16(temp11); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* +16 degrees offset for temp2 for the LM99 */ 10388c2ecf20Sopenharmony_ci if (data->kind == lm99 && index <= 2) 10398c2ecf20Sopenharmony_ci temp += 16000; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci return temp; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic int lm90_set_temp11(struct lm90_data *data, int index, long val) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci static struct reg { 10478c2ecf20Sopenharmony_ci u8 high; 10488c2ecf20Sopenharmony_ci u8 low; 10498c2ecf20Sopenharmony_ci } reg[] = { 10508c2ecf20Sopenharmony_ci [REMOTE_LOW] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL }, 10518c2ecf20Sopenharmony_ci [REMOTE_HIGH] = { LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL }, 10528c2ecf20Sopenharmony_ci [REMOTE_OFFSET] = { LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL }, 10538c2ecf20Sopenharmony_ci [REMOTE2_LOW] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL }, 10548c2ecf20Sopenharmony_ci [REMOTE2_HIGH] = { LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL } 10558c2ecf20Sopenharmony_ci }; 10568c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 10578c2ecf20Sopenharmony_ci struct reg *regp = ®[index]; 10588c2ecf20Sopenharmony_ci int err; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* +16 degrees offset for temp2 for the LM99 */ 10618c2ecf20Sopenharmony_ci if (data->kind == lm99 && index <= 2) 10628c2ecf20Sopenharmony_ci val -= 16000; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) 10658c2ecf20Sopenharmony_ci data->temp11[index] = temp_to_u16_adt7461(data, val); 10668c2ecf20Sopenharmony_ci else if (data->kind == max6646) 10678c2ecf20Sopenharmony_ci data->temp11[index] = temp_to_u8(val) << 8; 10688c2ecf20Sopenharmony_ci else if (data->flags & LM90_HAVE_REM_LIMIT_EXT) 10698c2ecf20Sopenharmony_ci data->temp11[index] = temp_to_s16(val); 10708c2ecf20Sopenharmony_ci else 10718c2ecf20Sopenharmony_ci data->temp11[index] = temp_to_s8(val) << 8; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, index >= 3); 10748c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(client, regp->high, 10758c2ecf20Sopenharmony_ci data->temp11[index] >> 8); 10768c2ecf20Sopenharmony_ci if (err < 0) 10778c2ecf20Sopenharmony_ci return err; 10788c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_REM_LIMIT_EXT) 10798c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(client, regp->low, 10808c2ecf20Sopenharmony_ci data->temp11[index] & 0xff); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, 0); 10838c2ecf20Sopenharmony_ci return err; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic int lm90_get_temp8(struct lm90_data *data, int index) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci s8 temp8 = data->temp8[index]; 10898c2ecf20Sopenharmony_ci int temp; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) 10928c2ecf20Sopenharmony_ci temp = temp_from_u8_adt7461(data, temp8); 10938c2ecf20Sopenharmony_ci else if (data->kind == max6646) 10948c2ecf20Sopenharmony_ci temp = temp_from_u8(temp8); 10958c2ecf20Sopenharmony_ci else 10968c2ecf20Sopenharmony_ci temp = temp_from_s8(temp8); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* +16 degrees offset for temp2 for the LM99 */ 10998c2ecf20Sopenharmony_ci if (data->kind == lm99 && index == 3) 11008c2ecf20Sopenharmony_ci temp += 16000; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return temp; 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic int lm90_set_temp8(struct lm90_data *data, int index, long val) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci static const u8 reg[TEMP8_REG_NUM] = { 11088c2ecf20Sopenharmony_ci LM90_REG_W_LOCAL_LOW, 11098c2ecf20Sopenharmony_ci LM90_REG_W_LOCAL_HIGH, 11108c2ecf20Sopenharmony_ci LM90_REG_W_LOCAL_CRIT, 11118c2ecf20Sopenharmony_ci LM90_REG_W_REMOTE_CRIT, 11128c2ecf20Sopenharmony_ci MAX6659_REG_W_LOCAL_EMERG, 11138c2ecf20Sopenharmony_ci MAX6659_REG_W_REMOTE_EMERG, 11148c2ecf20Sopenharmony_ci LM90_REG_W_REMOTE_CRIT, 11158c2ecf20Sopenharmony_ci MAX6659_REG_W_REMOTE_EMERG, 11168c2ecf20Sopenharmony_ci }; 11178c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 11188c2ecf20Sopenharmony_ci int err; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* +16 degrees offset for temp2 for the LM99 */ 11218c2ecf20Sopenharmony_ci if (data->kind == lm99 && index == 3) 11228c2ecf20Sopenharmony_ci val -= 16000; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) 11258c2ecf20Sopenharmony_ci data->temp8[index] = temp_to_u8_adt7461(data, val); 11268c2ecf20Sopenharmony_ci else if (data->kind == max6646) 11278c2ecf20Sopenharmony_ci data->temp8[index] = temp_to_u8(val); 11288c2ecf20Sopenharmony_ci else 11298c2ecf20Sopenharmony_ci data->temp8[index] = temp_to_s8(val); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, index >= 6); 11328c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]); 11338c2ecf20Sopenharmony_ci lm90_select_remote_channel(data, 0); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return err; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic int lm90_get_temphyst(struct lm90_data *data, int index) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci int temp; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) 11438c2ecf20Sopenharmony_ci temp = temp_from_u8_adt7461(data, data->temp8[index]); 11448c2ecf20Sopenharmony_ci else if (data->kind == max6646) 11458c2ecf20Sopenharmony_ci temp = temp_from_u8(data->temp8[index]); 11468c2ecf20Sopenharmony_ci else 11478c2ecf20Sopenharmony_ci temp = temp_from_s8(data->temp8[index]); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* +16 degrees offset for temp2 for the LM99 */ 11508c2ecf20Sopenharmony_ci if (data->kind == lm99 && index == 3) 11518c2ecf20Sopenharmony_ci temp += 16000; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return temp - temp_from_s8(data->temp_hyst); 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic int lm90_set_temphyst(struct lm90_data *data, long val) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 11598c2ecf20Sopenharmony_ci int temp; 11608c2ecf20Sopenharmony_ci int err; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) 11638c2ecf20Sopenharmony_ci temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]); 11648c2ecf20Sopenharmony_ci else if (data->kind == max6646) 11658c2ecf20Sopenharmony_ci temp = temp_from_u8(data->temp8[LOCAL_CRIT]); 11668c2ecf20Sopenharmony_ci else 11678c2ecf20Sopenharmony_ci temp = temp_from_s8(data->temp8[LOCAL_CRIT]); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci data->temp_hyst = hyst_to_reg(temp - val); 11708c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, 11718c2ecf20Sopenharmony_ci data->temp_hyst); 11728c2ecf20Sopenharmony_ci return err; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic const u8 lm90_temp_index[3] = { 11768c2ecf20Sopenharmony_ci LOCAL_TEMP, REMOTE_TEMP, REMOTE2_TEMP 11778c2ecf20Sopenharmony_ci}; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic const u8 lm90_temp_min_index[3] = { 11808c2ecf20Sopenharmony_ci LOCAL_LOW, REMOTE_LOW, REMOTE2_LOW 11818c2ecf20Sopenharmony_ci}; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic const u8 lm90_temp_max_index[3] = { 11848c2ecf20Sopenharmony_ci LOCAL_HIGH, REMOTE_HIGH, REMOTE2_HIGH 11858c2ecf20Sopenharmony_ci}; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic const u8 lm90_temp_crit_index[3] = { 11888c2ecf20Sopenharmony_ci LOCAL_CRIT, REMOTE_CRIT, REMOTE2_CRIT 11898c2ecf20Sopenharmony_ci}; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic const u8 lm90_temp_emerg_index[3] = { 11928c2ecf20Sopenharmony_ci LOCAL_EMERG, REMOTE_EMERG, REMOTE2_EMERG 11938c2ecf20Sopenharmony_ci}; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 }; 11968c2ecf20Sopenharmony_cistatic const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 }; 11978c2ecf20Sopenharmony_cistatic const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 }; 11988c2ecf20Sopenharmony_cistatic const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 }; 11998c2ecf20Sopenharmony_cistatic const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 }; 12008c2ecf20Sopenharmony_cistatic const u8 lm90_fault_bits[3] = { 0, 2, 10 }; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct lm90_data *data = dev_get_drvdata(dev); 12058c2ecf20Sopenharmony_ci int err; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12088c2ecf20Sopenharmony_ci err = lm90_update_device(dev); 12098c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12108c2ecf20Sopenharmony_ci if (err) 12118c2ecf20Sopenharmony_ci return err; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci switch (attr) { 12148c2ecf20Sopenharmony_ci case hwmon_temp_input: 12158c2ecf20Sopenharmony_ci *val = lm90_get_temp11(data, lm90_temp_index[channel]); 12168c2ecf20Sopenharmony_ci break; 12178c2ecf20Sopenharmony_ci case hwmon_temp_min_alarm: 12188c2ecf20Sopenharmony_ci *val = (data->alarms >> lm90_min_alarm_bits[channel]) & 1; 12198c2ecf20Sopenharmony_ci break; 12208c2ecf20Sopenharmony_ci case hwmon_temp_max_alarm: 12218c2ecf20Sopenharmony_ci *val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1; 12228c2ecf20Sopenharmony_ci break; 12238c2ecf20Sopenharmony_ci case hwmon_temp_crit_alarm: 12248c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_CRIT_ALRM_SWP) 12258c2ecf20Sopenharmony_ci *val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1; 12268c2ecf20Sopenharmony_ci else 12278c2ecf20Sopenharmony_ci *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1; 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci case hwmon_temp_emergency_alarm: 12308c2ecf20Sopenharmony_ci *val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1; 12318c2ecf20Sopenharmony_ci break; 12328c2ecf20Sopenharmony_ci case hwmon_temp_fault: 12338c2ecf20Sopenharmony_ci *val = (data->alarms >> lm90_fault_bits[channel]) & 1; 12348c2ecf20Sopenharmony_ci break; 12358c2ecf20Sopenharmony_ci case hwmon_temp_min: 12368c2ecf20Sopenharmony_ci if (channel == 0) 12378c2ecf20Sopenharmony_ci *val = lm90_get_temp8(data, 12388c2ecf20Sopenharmony_ci lm90_temp_min_index[channel]); 12398c2ecf20Sopenharmony_ci else 12408c2ecf20Sopenharmony_ci *val = lm90_get_temp11(data, 12418c2ecf20Sopenharmony_ci lm90_temp_min_index[channel]); 12428c2ecf20Sopenharmony_ci break; 12438c2ecf20Sopenharmony_ci case hwmon_temp_max: 12448c2ecf20Sopenharmony_ci if (channel == 0) 12458c2ecf20Sopenharmony_ci *val = lm90_get_temp8(data, 12468c2ecf20Sopenharmony_ci lm90_temp_max_index[channel]); 12478c2ecf20Sopenharmony_ci else 12488c2ecf20Sopenharmony_ci *val = lm90_get_temp11(data, 12498c2ecf20Sopenharmony_ci lm90_temp_max_index[channel]); 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci case hwmon_temp_crit: 12528c2ecf20Sopenharmony_ci *val = lm90_get_temp8(data, lm90_temp_crit_index[channel]); 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci case hwmon_temp_crit_hyst: 12558c2ecf20Sopenharmony_ci *val = lm90_get_temphyst(data, lm90_temp_crit_index[channel]); 12568c2ecf20Sopenharmony_ci break; 12578c2ecf20Sopenharmony_ci case hwmon_temp_emergency: 12588c2ecf20Sopenharmony_ci *val = lm90_get_temp8(data, lm90_temp_emerg_index[channel]); 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci case hwmon_temp_emergency_hyst: 12618c2ecf20Sopenharmony_ci *val = lm90_get_temphyst(data, lm90_temp_emerg_index[channel]); 12628c2ecf20Sopenharmony_ci break; 12638c2ecf20Sopenharmony_ci case hwmon_temp_offset: 12648c2ecf20Sopenharmony_ci *val = lm90_get_temp11(data, REMOTE_OFFSET); 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci default: 12678c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci return 0; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic int lm90_temp_write(struct device *dev, u32 attr, int channel, long val) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci struct lm90_data *data = dev_get_drvdata(dev); 12758c2ecf20Sopenharmony_ci int err; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci err = lm90_update_device(dev); 12808c2ecf20Sopenharmony_ci if (err) 12818c2ecf20Sopenharmony_ci goto error; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci switch (attr) { 12848c2ecf20Sopenharmony_ci case hwmon_temp_min: 12858c2ecf20Sopenharmony_ci if (channel == 0) 12868c2ecf20Sopenharmony_ci err = lm90_set_temp8(data, 12878c2ecf20Sopenharmony_ci lm90_temp_min_index[channel], 12888c2ecf20Sopenharmony_ci val); 12898c2ecf20Sopenharmony_ci else 12908c2ecf20Sopenharmony_ci err = lm90_set_temp11(data, 12918c2ecf20Sopenharmony_ci lm90_temp_min_index[channel], 12928c2ecf20Sopenharmony_ci val); 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci case hwmon_temp_max: 12958c2ecf20Sopenharmony_ci if (channel == 0) 12968c2ecf20Sopenharmony_ci err = lm90_set_temp8(data, 12978c2ecf20Sopenharmony_ci lm90_temp_max_index[channel], 12988c2ecf20Sopenharmony_ci val); 12998c2ecf20Sopenharmony_ci else 13008c2ecf20Sopenharmony_ci err = lm90_set_temp11(data, 13018c2ecf20Sopenharmony_ci lm90_temp_max_index[channel], 13028c2ecf20Sopenharmony_ci val); 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci case hwmon_temp_crit: 13058c2ecf20Sopenharmony_ci err = lm90_set_temp8(data, lm90_temp_crit_index[channel], val); 13068c2ecf20Sopenharmony_ci break; 13078c2ecf20Sopenharmony_ci case hwmon_temp_crit_hyst: 13088c2ecf20Sopenharmony_ci err = lm90_set_temphyst(data, val); 13098c2ecf20Sopenharmony_ci break; 13108c2ecf20Sopenharmony_ci case hwmon_temp_emergency: 13118c2ecf20Sopenharmony_ci err = lm90_set_temp8(data, lm90_temp_emerg_index[channel], val); 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci case hwmon_temp_offset: 13148c2ecf20Sopenharmony_ci err = lm90_set_temp11(data, REMOTE_OFFSET, val); 13158c2ecf20Sopenharmony_ci break; 13168c2ecf20Sopenharmony_ci default: 13178c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_cierror: 13218c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci return err; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic umode_t lm90_temp_is_visible(const void *data, u32 attr, int channel) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci switch (attr) { 13298c2ecf20Sopenharmony_ci case hwmon_temp_input: 13308c2ecf20Sopenharmony_ci case hwmon_temp_min_alarm: 13318c2ecf20Sopenharmony_ci case hwmon_temp_max_alarm: 13328c2ecf20Sopenharmony_ci case hwmon_temp_crit_alarm: 13338c2ecf20Sopenharmony_ci case hwmon_temp_emergency_alarm: 13348c2ecf20Sopenharmony_ci case hwmon_temp_emergency_hyst: 13358c2ecf20Sopenharmony_ci case hwmon_temp_fault: 13368c2ecf20Sopenharmony_ci return 0444; 13378c2ecf20Sopenharmony_ci case hwmon_temp_min: 13388c2ecf20Sopenharmony_ci case hwmon_temp_max: 13398c2ecf20Sopenharmony_ci case hwmon_temp_crit: 13408c2ecf20Sopenharmony_ci case hwmon_temp_emergency: 13418c2ecf20Sopenharmony_ci case hwmon_temp_offset: 13428c2ecf20Sopenharmony_ci return 0644; 13438c2ecf20Sopenharmony_ci case hwmon_temp_crit_hyst: 13448c2ecf20Sopenharmony_ci if (channel == 0) 13458c2ecf20Sopenharmony_ci return 0644; 13468c2ecf20Sopenharmony_ci return 0444; 13478c2ecf20Sopenharmony_ci default: 13488c2ecf20Sopenharmony_ci return 0; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cistatic int lm90_chip_read(struct device *dev, u32 attr, int channel, long *val) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci struct lm90_data *data = dev_get_drvdata(dev); 13558c2ecf20Sopenharmony_ci int err; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13588c2ecf20Sopenharmony_ci err = lm90_update_device(dev); 13598c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13608c2ecf20Sopenharmony_ci if (err) 13618c2ecf20Sopenharmony_ci return err; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci switch (attr) { 13648c2ecf20Sopenharmony_ci case hwmon_chip_update_interval: 13658c2ecf20Sopenharmony_ci *val = data->update_interval; 13668c2ecf20Sopenharmony_ci break; 13678c2ecf20Sopenharmony_ci case hwmon_chip_alarms: 13688c2ecf20Sopenharmony_ci *val = data->alarms; 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci default: 13718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return 0; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic int lm90_chip_write(struct device *dev, u32 attr, int channel, long val) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci struct lm90_data *data = dev_get_drvdata(dev); 13808c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 13818c2ecf20Sopenharmony_ci int err; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci err = lm90_update_device(dev); 13868c2ecf20Sopenharmony_ci if (err) 13878c2ecf20Sopenharmony_ci goto error; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci switch (attr) { 13908c2ecf20Sopenharmony_ci case hwmon_chip_update_interval: 13918c2ecf20Sopenharmony_ci err = lm90_set_convrate(client, data, 13928c2ecf20Sopenharmony_ci clamp_val(val, 0, 100000)); 13938c2ecf20Sopenharmony_ci break; 13948c2ecf20Sopenharmony_ci default: 13958c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 13968c2ecf20Sopenharmony_ci break; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_cierror: 13998c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci return err; 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic umode_t lm90_chip_is_visible(const void *data, u32 attr, int channel) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci switch (attr) { 14078c2ecf20Sopenharmony_ci case hwmon_chip_update_interval: 14088c2ecf20Sopenharmony_ci return 0644; 14098c2ecf20Sopenharmony_ci case hwmon_chip_alarms: 14108c2ecf20Sopenharmony_ci return 0444; 14118c2ecf20Sopenharmony_ci default: 14128c2ecf20Sopenharmony_ci return 0; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic int lm90_read(struct device *dev, enum hwmon_sensor_types type, 14178c2ecf20Sopenharmony_ci u32 attr, int channel, long *val) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci switch (type) { 14208c2ecf20Sopenharmony_ci case hwmon_chip: 14218c2ecf20Sopenharmony_ci return lm90_chip_read(dev, attr, channel, val); 14228c2ecf20Sopenharmony_ci case hwmon_temp: 14238c2ecf20Sopenharmony_ci return lm90_temp_read(dev, attr, channel, val); 14248c2ecf20Sopenharmony_ci default: 14258c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic int lm90_write(struct device *dev, enum hwmon_sensor_types type, 14308c2ecf20Sopenharmony_ci u32 attr, int channel, long val) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci switch (type) { 14338c2ecf20Sopenharmony_ci case hwmon_chip: 14348c2ecf20Sopenharmony_ci return lm90_chip_write(dev, attr, channel, val); 14358c2ecf20Sopenharmony_ci case hwmon_temp: 14368c2ecf20Sopenharmony_ci return lm90_temp_write(dev, attr, channel, val); 14378c2ecf20Sopenharmony_ci default: 14388c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cistatic umode_t lm90_is_visible(const void *data, enum hwmon_sensor_types type, 14438c2ecf20Sopenharmony_ci u32 attr, int channel) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci switch (type) { 14468c2ecf20Sopenharmony_ci case hwmon_chip: 14478c2ecf20Sopenharmony_ci return lm90_chip_is_visible(data, attr, channel); 14488c2ecf20Sopenharmony_ci case hwmon_temp: 14498c2ecf20Sopenharmony_ci return lm90_temp_is_visible(data, attr, channel); 14508c2ecf20Sopenharmony_ci default: 14518c2ecf20Sopenharmony_ci return 0; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 14568c2ecf20Sopenharmony_cistatic int lm90_detect(struct i2c_client *client, 14578c2ecf20Sopenharmony_ci struct i2c_board_info *info) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 14608c2ecf20Sopenharmony_ci int address = client->addr; 14618c2ecf20Sopenharmony_ci const char *name = NULL; 14628c2ecf20Sopenharmony_ci int man_id, chip_id, config1, config2, convrate; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 14658c2ecf20Sopenharmony_ci return -ENODEV; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci /* detection and identification */ 14688c2ecf20Sopenharmony_ci man_id = i2c_smbus_read_byte_data(client, LM90_REG_R_MAN_ID); 14698c2ecf20Sopenharmony_ci chip_id = i2c_smbus_read_byte_data(client, LM90_REG_R_CHIP_ID); 14708c2ecf20Sopenharmony_ci config1 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); 14718c2ecf20Sopenharmony_ci convrate = i2c_smbus_read_byte_data(client, LM90_REG_R_CONVRATE); 14728c2ecf20Sopenharmony_ci if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0) 14738c2ecf20Sopenharmony_ci return -ENODEV; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (man_id == 0x01 || man_id == 0x5C || man_id == 0xA1) { 14768c2ecf20Sopenharmony_ci config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2); 14778c2ecf20Sopenharmony_ci if (config2 < 0) 14788c2ecf20Sopenharmony_ci return -ENODEV; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if ((address == 0x4C || address == 0x4D) 14828c2ecf20Sopenharmony_ci && man_id == 0x01) { /* National Semiconductor */ 14838c2ecf20Sopenharmony_ci if ((config1 & 0x2A) == 0x00 14848c2ecf20Sopenharmony_ci && (config2 & 0xF8) == 0x00 14858c2ecf20Sopenharmony_ci && convrate <= 0x09) { 14868c2ecf20Sopenharmony_ci if (address == 0x4C 14878c2ecf20Sopenharmony_ci && (chip_id & 0xF0) == 0x20) { /* LM90 */ 14888c2ecf20Sopenharmony_ci name = "lm90"; 14898c2ecf20Sopenharmony_ci } else 14908c2ecf20Sopenharmony_ci if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ 14918c2ecf20Sopenharmony_ci name = "lm99"; 14928c2ecf20Sopenharmony_ci dev_info(&adapter->dev, 14938c2ecf20Sopenharmony_ci "Assuming LM99 chip at 0x%02x\n", 14948c2ecf20Sopenharmony_ci address); 14958c2ecf20Sopenharmony_ci dev_info(&adapter->dev, 14968c2ecf20Sopenharmony_ci "If it is an LM89, instantiate it " 14978c2ecf20Sopenharmony_ci "with the new_device sysfs " 14988c2ecf20Sopenharmony_ci "interface\n"); 14998c2ecf20Sopenharmony_ci } else 15008c2ecf20Sopenharmony_ci if (address == 0x4C 15018c2ecf20Sopenharmony_ci && (chip_id & 0xF0) == 0x10) { /* LM86 */ 15028c2ecf20Sopenharmony_ci name = "lm86"; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci } else 15068c2ecf20Sopenharmony_ci if ((address == 0x4C || address == 0x4D) 15078c2ecf20Sopenharmony_ci && man_id == 0x41) { /* Analog Devices */ 15088c2ecf20Sopenharmony_ci if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ 15098c2ecf20Sopenharmony_ci && (config1 & 0x3F) == 0x00 15108c2ecf20Sopenharmony_ci && convrate <= 0x0A) { 15118c2ecf20Sopenharmony_ci name = "adm1032"; 15128c2ecf20Sopenharmony_ci /* 15138c2ecf20Sopenharmony_ci * The ADM1032 supports PEC, but only if combined 15148c2ecf20Sopenharmony_ci * transactions are not used. 15158c2ecf20Sopenharmony_ci */ 15168c2ecf20Sopenharmony_ci if (i2c_check_functionality(adapter, 15178c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE)) 15188c2ecf20Sopenharmony_ci info->flags |= I2C_CLIENT_PEC; 15198c2ecf20Sopenharmony_ci } else 15208c2ecf20Sopenharmony_ci if (chip_id == 0x51 /* ADT7461 */ 15218c2ecf20Sopenharmony_ci && (config1 & 0x1B) == 0x00 15228c2ecf20Sopenharmony_ci && convrate <= 0x0A) { 15238c2ecf20Sopenharmony_ci name = "adt7461"; 15248c2ecf20Sopenharmony_ci } else 15258c2ecf20Sopenharmony_ci if (chip_id == 0x57 /* ADT7461A, NCT1008 */ 15268c2ecf20Sopenharmony_ci && (config1 & 0x1B) == 0x00 15278c2ecf20Sopenharmony_ci && convrate <= 0x0A) { 15288c2ecf20Sopenharmony_ci name = "adt7461a"; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci } else 15318c2ecf20Sopenharmony_ci if (man_id == 0x4D) { /* Maxim */ 15328c2ecf20Sopenharmony_ci int emerg, emerg2, status2; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* 15358c2ecf20Sopenharmony_ci * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read 15368c2ecf20Sopenharmony_ci * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG 15378c2ecf20Sopenharmony_ci * exists, both readings will reflect the same value. Otherwise, 15388c2ecf20Sopenharmony_ci * the readings will be different. 15398c2ecf20Sopenharmony_ci */ 15408c2ecf20Sopenharmony_ci emerg = i2c_smbus_read_byte_data(client, 15418c2ecf20Sopenharmony_ci MAX6659_REG_R_REMOTE_EMERG); 15428c2ecf20Sopenharmony_ci man_id = i2c_smbus_read_byte_data(client, 15438c2ecf20Sopenharmony_ci LM90_REG_R_MAN_ID); 15448c2ecf20Sopenharmony_ci emerg2 = i2c_smbus_read_byte_data(client, 15458c2ecf20Sopenharmony_ci MAX6659_REG_R_REMOTE_EMERG); 15468c2ecf20Sopenharmony_ci status2 = i2c_smbus_read_byte_data(client, 15478c2ecf20Sopenharmony_ci MAX6696_REG_R_STATUS2); 15488c2ecf20Sopenharmony_ci if (emerg < 0 || man_id < 0 || emerg2 < 0 || status2 < 0) 15498c2ecf20Sopenharmony_ci return -ENODEV; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* 15528c2ecf20Sopenharmony_ci * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id 15538c2ecf20Sopenharmony_ci * register. Reading from that address will return the last 15548c2ecf20Sopenharmony_ci * read value, which in our case is those of the man_id 15558c2ecf20Sopenharmony_ci * register. Likewise, the config1 register seems to lack a 15568c2ecf20Sopenharmony_ci * low nibble, so the value will be those of the previous 15578c2ecf20Sopenharmony_ci * read, so in our case those of the man_id register. 15588c2ecf20Sopenharmony_ci * MAX6659 has a third set of upper temperature limit registers. 15598c2ecf20Sopenharmony_ci * Those registers also return values on MAX6657 and MAX6658, 15608c2ecf20Sopenharmony_ci * thus the only way to detect MAX6659 is by its address. 15618c2ecf20Sopenharmony_ci * For this reason it will be mis-detected as MAX6657 if its 15628c2ecf20Sopenharmony_ci * address is 0x4C. 15638c2ecf20Sopenharmony_ci */ 15648c2ecf20Sopenharmony_ci if (chip_id == man_id 15658c2ecf20Sopenharmony_ci && (address == 0x4C || address == 0x4D || address == 0x4E) 15668c2ecf20Sopenharmony_ci && (config1 & 0x1F) == (man_id & 0x0F) 15678c2ecf20Sopenharmony_ci && convrate <= 0x09) { 15688c2ecf20Sopenharmony_ci if (address == 0x4C) 15698c2ecf20Sopenharmony_ci name = "max6657"; 15708c2ecf20Sopenharmony_ci else 15718c2ecf20Sopenharmony_ci name = "max6659"; 15728c2ecf20Sopenharmony_ci } else 15738c2ecf20Sopenharmony_ci /* 15748c2ecf20Sopenharmony_ci * Even though MAX6695 and MAX6696 do not have a chip ID 15758c2ecf20Sopenharmony_ci * register, reading it returns 0x01. Bit 4 of the config1 15768c2ecf20Sopenharmony_ci * register is unused and should return zero when read. Bit 0 of 15778c2ecf20Sopenharmony_ci * the status2 register is unused and should return zero when 15788c2ecf20Sopenharmony_ci * read. 15798c2ecf20Sopenharmony_ci * 15808c2ecf20Sopenharmony_ci * MAX6695 and MAX6696 have an additional set of temperature 15818c2ecf20Sopenharmony_ci * limit registers. We can detect those chips by checking if 15828c2ecf20Sopenharmony_ci * one of those registers exists. 15838c2ecf20Sopenharmony_ci */ 15848c2ecf20Sopenharmony_ci if (chip_id == 0x01 15858c2ecf20Sopenharmony_ci && (config1 & 0x10) == 0x00 15868c2ecf20Sopenharmony_ci && (status2 & 0x01) == 0x00 15878c2ecf20Sopenharmony_ci && emerg == emerg2 15888c2ecf20Sopenharmony_ci && convrate <= 0x07) { 15898c2ecf20Sopenharmony_ci name = "max6696"; 15908c2ecf20Sopenharmony_ci } else 15918c2ecf20Sopenharmony_ci /* 15928c2ecf20Sopenharmony_ci * The chip_id register of the MAX6680 and MAX6681 holds the 15938c2ecf20Sopenharmony_ci * revision of the chip. The lowest bit of the config1 register 15948c2ecf20Sopenharmony_ci * is unused and should return zero when read, so should the 15958c2ecf20Sopenharmony_ci * second to last bit of config1 (software reset). 15968c2ecf20Sopenharmony_ci */ 15978c2ecf20Sopenharmony_ci if (chip_id == 0x01 15988c2ecf20Sopenharmony_ci && (config1 & 0x03) == 0x00 15998c2ecf20Sopenharmony_ci && convrate <= 0x07) { 16008c2ecf20Sopenharmony_ci name = "max6680"; 16018c2ecf20Sopenharmony_ci } else 16028c2ecf20Sopenharmony_ci /* 16038c2ecf20Sopenharmony_ci * The chip_id register of the MAX6646/6647/6649 holds the 16048c2ecf20Sopenharmony_ci * revision of the chip. The lowest 6 bits of the config1 16058c2ecf20Sopenharmony_ci * register are unused and should return zero when read. 16068c2ecf20Sopenharmony_ci */ 16078c2ecf20Sopenharmony_ci if (chip_id == 0x59 16088c2ecf20Sopenharmony_ci && (config1 & 0x3f) == 0x00 16098c2ecf20Sopenharmony_ci && convrate <= 0x07) { 16108c2ecf20Sopenharmony_ci name = "max6646"; 16118c2ecf20Sopenharmony_ci } else 16128c2ecf20Sopenharmony_ci /* 16138c2ecf20Sopenharmony_ci * The chip_id of the MAX6654 holds the revision of the chip. 16148c2ecf20Sopenharmony_ci * The lowest 3 bits of the config1 register are unused and 16158c2ecf20Sopenharmony_ci * should return zero when read. 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_ci if (chip_id == 0x08 16188c2ecf20Sopenharmony_ci && (config1 & 0x07) == 0x00 16198c2ecf20Sopenharmony_ci && convrate <= 0x07) { 16208c2ecf20Sopenharmony_ci name = "max6654"; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci } else 16238c2ecf20Sopenharmony_ci if (address == 0x4C 16248c2ecf20Sopenharmony_ci && man_id == 0x5C) { /* Winbond/Nuvoton */ 16258c2ecf20Sopenharmony_ci if ((config1 & 0x2A) == 0x00 16268c2ecf20Sopenharmony_ci && (config2 & 0xF8) == 0x00) { 16278c2ecf20Sopenharmony_ci if (chip_id == 0x01 /* W83L771W/G */ 16288c2ecf20Sopenharmony_ci && convrate <= 0x09) { 16298c2ecf20Sopenharmony_ci name = "w83l771"; 16308c2ecf20Sopenharmony_ci } else 16318c2ecf20Sopenharmony_ci if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */ 16328c2ecf20Sopenharmony_ci && convrate <= 0x08) { 16338c2ecf20Sopenharmony_ci name = "w83l771"; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci } else 16378c2ecf20Sopenharmony_ci if (address >= 0x48 && address <= 0x4F 16388c2ecf20Sopenharmony_ci && man_id == 0xA1) { /* NXP Semiconductor/Philips */ 16398c2ecf20Sopenharmony_ci if (chip_id == 0x00 16408c2ecf20Sopenharmony_ci && (config1 & 0x2A) == 0x00 16418c2ecf20Sopenharmony_ci && (config2 & 0xFE) == 0x00 16428c2ecf20Sopenharmony_ci && convrate <= 0x09) { 16438c2ecf20Sopenharmony_ci name = "sa56004"; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci } else 16468c2ecf20Sopenharmony_ci if ((address == 0x4C || address == 0x4D) 16478c2ecf20Sopenharmony_ci && man_id == 0x47) { /* GMT */ 16488c2ecf20Sopenharmony_ci if (chip_id == 0x01 /* G781 */ 16498c2ecf20Sopenharmony_ci && (config1 & 0x3F) == 0x00 16508c2ecf20Sopenharmony_ci && convrate <= 0x08) 16518c2ecf20Sopenharmony_ci name = "g781"; 16528c2ecf20Sopenharmony_ci } else 16538c2ecf20Sopenharmony_ci if (man_id == 0x55 && chip_id == 0x00 && 16548c2ecf20Sopenharmony_ci (config1 & 0x1B) == 0x00 && convrate <= 0x09) { 16558c2ecf20Sopenharmony_ci int local_ext, conalert, chen, dfc; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci local_ext = i2c_smbus_read_byte_data(client, 16588c2ecf20Sopenharmony_ci TMP451_REG_R_LOCAL_TEMPL); 16598c2ecf20Sopenharmony_ci conalert = i2c_smbus_read_byte_data(client, 16608c2ecf20Sopenharmony_ci TMP451_REG_CONALERT); 16618c2ecf20Sopenharmony_ci chen = i2c_smbus_read_byte_data(client, TMP461_REG_CHEN); 16628c2ecf20Sopenharmony_ci dfc = i2c_smbus_read_byte_data(client, TMP461_REG_DFC); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if ((local_ext & 0x0F) == 0x00 && 16658c2ecf20Sopenharmony_ci (conalert & 0xf1) == 0x01 && 16668c2ecf20Sopenharmony_ci (chen & 0xfc) == 0x00 && 16678c2ecf20Sopenharmony_ci (dfc & 0xfc) == 0x00) { 16688c2ecf20Sopenharmony_ci if (address == 0x4c && !(chen & 0x03)) 16698c2ecf20Sopenharmony_ci name = "tmp451"; 16708c2ecf20Sopenharmony_ci else if (address >= 0x48 && address <= 0x4f) 16718c2ecf20Sopenharmony_ci name = "tmp461"; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (!name) { /* identification failed */ 16768c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 16778c2ecf20Sopenharmony_ci "Unsupported chip at 0x%02x (man_id=0x%02X, " 16788c2ecf20Sopenharmony_ci "chip_id=0x%02X)\n", address, man_id, chip_id); 16798c2ecf20Sopenharmony_ci return -ENODEV; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci strlcpy(info->type, name, I2C_NAME_SIZE); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci return 0; 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic void lm90_restore_conf(void *_data) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci struct lm90_data *data = _data; 16908c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci /* Restore initial configuration */ 16938c2ecf20Sopenharmony_ci lm90_write_convrate(data, data->convrate_orig); 16948c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, 16958c2ecf20Sopenharmony_ci data->config_orig); 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic int lm90_init_client(struct i2c_client *client, struct lm90_data *data) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci int config, convrate; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci convrate = lm90_read_reg(client, LM90_REG_R_CONVRATE); 17038c2ecf20Sopenharmony_ci if (convrate < 0) 17048c2ecf20Sopenharmony_ci return convrate; 17058c2ecf20Sopenharmony_ci data->convrate_orig = convrate; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci /* 17088c2ecf20Sopenharmony_ci * Start the conversions. 17098c2ecf20Sopenharmony_ci */ 17108c2ecf20Sopenharmony_ci config = lm90_read_reg(client, LM90_REG_R_CONFIG1); 17118c2ecf20Sopenharmony_ci if (config < 0) 17128c2ecf20Sopenharmony_ci return config; 17138c2ecf20Sopenharmony_ci data->config_orig = config; 17148c2ecf20Sopenharmony_ci data->config = config; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */ 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci /* Check Temperature Range Select */ 17198c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EXTENDED_TEMP) { 17208c2ecf20Sopenharmony_ci if (config & 0x04) 17218c2ecf20Sopenharmony_ci data->flags |= LM90_FLAG_ADT7461_EXT; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci /* 17258c2ecf20Sopenharmony_ci * Put MAX6680/MAX8881 into extended resolution (bit 0x10, 17268c2ecf20Sopenharmony_ci * 0.125 degree resolution) and range (0x08, extend range 17278c2ecf20Sopenharmony_ci * to -64 degree) mode for the remote temperature sensor. 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_ci if (data->kind == max6680) 17308c2ecf20Sopenharmony_ci config |= 0x18; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* 17338c2ecf20Sopenharmony_ci * Put MAX6654 into extended range (0x20, extend minimum range from 17348c2ecf20Sopenharmony_ci * 0 degrees to -64 degrees). Note that extended resolution is not 17358c2ecf20Sopenharmony_ci * possible on the MAX6654 unless conversion rate is set to 1 Hz or 17368c2ecf20Sopenharmony_ci * slower, which is intentionally not done by default. 17378c2ecf20Sopenharmony_ci */ 17388c2ecf20Sopenharmony_ci if (data->kind == max6654) 17398c2ecf20Sopenharmony_ci config |= 0x20; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci /* 17428c2ecf20Sopenharmony_ci * Select external channel 0 for max6695/96 17438c2ecf20Sopenharmony_ci */ 17448c2ecf20Sopenharmony_ci if (data->kind == max6696) 17458c2ecf20Sopenharmony_ci config &= ~0x08; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci config &= 0xBF; /* run */ 17488c2ecf20Sopenharmony_ci lm90_update_confreg(data, config); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data); 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic bool lm90_is_tripped(struct i2c_client *client, u16 *status) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci struct lm90_data *data = i2c_get_clientdata(client); 17568c2ecf20Sopenharmony_ci int st, st2 = 0; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci st = lm90_read_reg(client, LM90_REG_R_STATUS); 17598c2ecf20Sopenharmony_ci if (st < 0) 17608c2ecf20Sopenharmony_ci return false; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (data->kind == max6696) { 17638c2ecf20Sopenharmony_ci st2 = lm90_read_reg(client, MAX6696_REG_R_STATUS2); 17648c2ecf20Sopenharmony_ci if (st2 < 0) 17658c2ecf20Sopenharmony_ci return false; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci *status = st | (st2 << 8); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if ((st & 0x7f) == 0 && (st2 & 0xfe) == 0) 17718c2ecf20Sopenharmony_ci return false; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) || 17748c2ecf20Sopenharmony_ci (st2 & MAX6696_STATUS2_LOT2)) 17758c2ecf20Sopenharmony_ci dev_warn(&client->dev, 17768c2ecf20Sopenharmony_ci "temp%d out of range, please check!\n", 1); 17778c2ecf20Sopenharmony_ci if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) || 17788c2ecf20Sopenharmony_ci (st2 & MAX6696_STATUS2_ROT2)) 17798c2ecf20Sopenharmony_ci dev_warn(&client->dev, 17808c2ecf20Sopenharmony_ci "temp%d out of range, please check!\n", 2); 17818c2ecf20Sopenharmony_ci if (st & LM90_STATUS_ROPEN) 17828c2ecf20Sopenharmony_ci dev_warn(&client->dev, 17838c2ecf20Sopenharmony_ci "temp%d diode open, please check!\n", 2); 17848c2ecf20Sopenharmony_ci if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH | 17858c2ecf20Sopenharmony_ci MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2)) 17868c2ecf20Sopenharmony_ci dev_warn(&client->dev, 17878c2ecf20Sopenharmony_ci "temp%d out of range, please check!\n", 3); 17888c2ecf20Sopenharmony_ci if (st2 & MAX6696_STATUS2_R2OPEN) 17898c2ecf20Sopenharmony_ci dev_warn(&client->dev, 17908c2ecf20Sopenharmony_ci "temp%d diode open, please check!\n", 3); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci return true; 17938c2ecf20Sopenharmony_ci} 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cistatic irqreturn_t lm90_irq_thread(int irq, void *dev_id) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci struct i2c_client *client = dev_id; 17988c2ecf20Sopenharmony_ci u16 status; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (lm90_is_tripped(client, &status)) 18018c2ecf20Sopenharmony_ci return IRQ_HANDLED; 18028c2ecf20Sopenharmony_ci else 18038c2ecf20Sopenharmony_ci return IRQ_NONE; 18048c2ecf20Sopenharmony_ci} 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_cistatic void lm90_remove_pec(void *dev) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_pec); 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic void lm90_regulator_disable(void *regulator) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci regulator_disable(regulator); 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_cistatic const struct hwmon_ops lm90_ops = { 18188c2ecf20Sopenharmony_ci .is_visible = lm90_is_visible, 18198c2ecf20Sopenharmony_ci .read = lm90_read, 18208c2ecf20Sopenharmony_ci .write = lm90_write, 18218c2ecf20Sopenharmony_ci}; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic int lm90_probe(struct i2c_client *client) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 18268c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 18278c2ecf20Sopenharmony_ci struct hwmon_channel_info *info; 18288c2ecf20Sopenharmony_ci struct regulator *regulator; 18298c2ecf20Sopenharmony_ci struct device *hwmon_dev; 18308c2ecf20Sopenharmony_ci struct lm90_data *data; 18318c2ecf20Sopenharmony_ci int err; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci regulator = devm_regulator_get(dev, "vcc"); 18348c2ecf20Sopenharmony_ci if (IS_ERR(regulator)) 18358c2ecf20Sopenharmony_ci return PTR_ERR(regulator); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci err = regulator_enable(regulator); 18388c2ecf20Sopenharmony_ci if (err < 0) { 18398c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable regulator: %d\n", err); 18408c2ecf20Sopenharmony_ci return err; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(dev, lm90_regulator_disable, regulator); 18448c2ecf20Sopenharmony_ci if (err) 18458c2ecf20Sopenharmony_ci return err; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL); 18488c2ecf20Sopenharmony_ci if (!data) 18498c2ecf20Sopenharmony_ci return -ENOMEM; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci data->client = client; 18528c2ecf20Sopenharmony_ci i2c_set_clientdata(client, data); 18538c2ecf20Sopenharmony_ci mutex_init(&data->update_lock); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* Set the device type */ 18568c2ecf20Sopenharmony_ci if (client->dev.of_node) 18578c2ecf20Sopenharmony_ci data->kind = (enum chips)of_device_get_match_data(&client->dev); 18588c2ecf20Sopenharmony_ci else 18598c2ecf20Sopenharmony_ci data->kind = i2c_match_id(lm90_id, client)->driver_data; 18608c2ecf20Sopenharmony_ci if (data->kind == adm1032) { 18618c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 18628c2ecf20Sopenharmony_ci client->flags &= ~I2C_CLIENT_PEC; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci /* 18668c2ecf20Sopenharmony_ci * Different devices have different alarm bits triggering the 18678c2ecf20Sopenharmony_ci * ALERT# output 18688c2ecf20Sopenharmony_ci */ 18698c2ecf20Sopenharmony_ci data->alert_alarms = lm90_params[data->kind].alert_alarms; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci /* Set chip capabilities */ 18728c2ecf20Sopenharmony_ci data->flags = lm90_params[data->kind].flags; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci data->chip.ops = &lm90_ops; 18758c2ecf20Sopenharmony_ci data->chip.info = data->info; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci data->info[0] = HWMON_CHANNEL_INFO(chip, 18788c2ecf20Sopenharmony_ci HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL | HWMON_C_ALARMS); 18798c2ecf20Sopenharmony_ci data->info[1] = &data->temp_info; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci info = &data->temp_info; 18828c2ecf20Sopenharmony_ci info->type = hwmon_temp; 18838c2ecf20Sopenharmony_ci info->config = data->channel_config; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | 18868c2ecf20Sopenharmony_ci HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM; 18878c2ecf20Sopenharmony_ci data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | 18888c2ecf20Sopenharmony_ci HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_FAULT; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_CRIT) { 18918c2ecf20Sopenharmony_ci data->channel_config[0] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST; 18928c2ecf20Sopenharmony_ci data->channel_config[1] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_OFFSET) 18968c2ecf20Sopenharmony_ci data->channel_config[1] |= HWMON_T_OFFSET; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EMERGENCY) { 18998c2ecf20Sopenharmony_ci data->channel_config[0] |= HWMON_T_EMERGENCY | 19008c2ecf20Sopenharmony_ci HWMON_T_EMERGENCY_HYST; 19018c2ecf20Sopenharmony_ci data->channel_config[1] |= HWMON_T_EMERGENCY | 19028c2ecf20Sopenharmony_ci HWMON_T_EMERGENCY_HYST; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_EMERGENCY_ALARM) { 19068c2ecf20Sopenharmony_ci data->channel_config[0] |= HWMON_T_EMERGENCY_ALARM; 19078c2ecf20Sopenharmony_ci data->channel_config[1] |= HWMON_T_EMERGENCY_ALARM; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (data->flags & LM90_HAVE_TEMP3) { 19118c2ecf20Sopenharmony_ci data->channel_config[2] = HWMON_T_INPUT | 19128c2ecf20Sopenharmony_ci HWMON_T_MIN | HWMON_T_MAX | 19138c2ecf20Sopenharmony_ci HWMON_T_CRIT | HWMON_T_CRIT_HYST | 19148c2ecf20Sopenharmony_ci HWMON_T_EMERGENCY | HWMON_T_EMERGENCY_HYST | 19158c2ecf20Sopenharmony_ci HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | 19168c2ecf20Sopenharmony_ci HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM | 19178c2ecf20Sopenharmony_ci HWMON_T_FAULT; 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci data->reg_local_ext = lm90_params[data->kind].reg_local_ext; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci /* Set maximum conversion rate */ 19238c2ecf20Sopenharmony_ci data->max_convrate = lm90_params[data->kind].max_convrate; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci /* Initialize the LM90 chip */ 19268c2ecf20Sopenharmony_ci err = lm90_init_client(client, data); 19278c2ecf20Sopenharmony_ci if (err < 0) { 19288c2ecf20Sopenharmony_ci dev_err(dev, "Failed to initialize device\n"); 19298c2ecf20Sopenharmony_ci return err; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* 19338c2ecf20Sopenharmony_ci * The 'pec' attribute is attached to the i2c device and thus created 19348c2ecf20Sopenharmony_ci * separately. 19358c2ecf20Sopenharmony_ci */ 19368c2ecf20Sopenharmony_ci if (client->flags & I2C_CLIENT_PEC) { 19378c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_pec); 19388c2ecf20Sopenharmony_ci if (err) 19398c2ecf20Sopenharmony_ci return err; 19408c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(dev, lm90_remove_pec, dev); 19418c2ecf20Sopenharmony_ci if (err) 19428c2ecf20Sopenharmony_ci return err; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 19468c2ecf20Sopenharmony_ci data, &data->chip, 19478c2ecf20Sopenharmony_ci NULL); 19488c2ecf20Sopenharmony_ci if (IS_ERR(hwmon_dev)) 19498c2ecf20Sopenharmony_ci return PTR_ERR(hwmon_dev); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (client->irq) { 19528c2ecf20Sopenharmony_ci dev_dbg(dev, "IRQ: %d\n", client->irq); 19538c2ecf20Sopenharmony_ci err = devm_request_threaded_irq(dev, client->irq, 19548c2ecf20Sopenharmony_ci NULL, lm90_irq_thread, 19558c2ecf20Sopenharmony_ci IRQF_TRIGGER_LOW | IRQF_ONESHOT, 19568c2ecf20Sopenharmony_ci "lm90", client); 19578c2ecf20Sopenharmony_ci if (err < 0) { 19588c2ecf20Sopenharmony_ci dev_err(dev, "cannot request IRQ %d\n", client->irq); 19598c2ecf20Sopenharmony_ci return err; 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci return 0; 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, 19678c2ecf20Sopenharmony_ci unsigned int flag) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci u16 alarms; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci if (type != I2C_PROTOCOL_SMBUS_ALERT) 19728c2ecf20Sopenharmony_ci return; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (lm90_is_tripped(client, &alarms)) { 19758c2ecf20Sopenharmony_ci /* 19768c2ecf20Sopenharmony_ci * Disable ALERT# output, because these chips don't implement 19778c2ecf20Sopenharmony_ci * SMBus alert correctly; they should only hold the alert line 19788c2ecf20Sopenharmony_ci * low briefly. 19798c2ecf20Sopenharmony_ci */ 19808c2ecf20Sopenharmony_ci struct lm90_data *data = i2c_get_clientdata(client); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if ((data->flags & LM90_HAVE_BROKEN_ALERT) && 19838c2ecf20Sopenharmony_ci (alarms & data->alert_alarms)) { 19848c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Disabling ALERT#\n"); 19858c2ecf20Sopenharmony_ci lm90_update_confreg(data, data->config | 0x80); 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci } else { 19888c2ecf20Sopenharmony_ci dev_info(&client->dev, "Everything OK\n"); 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic struct i2c_driver lm90_driver = { 19938c2ecf20Sopenharmony_ci .class = I2C_CLASS_HWMON, 19948c2ecf20Sopenharmony_ci .driver = { 19958c2ecf20Sopenharmony_ci .name = "lm90", 19968c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(lm90_of_match), 19978c2ecf20Sopenharmony_ci }, 19988c2ecf20Sopenharmony_ci .probe_new = lm90_probe, 19998c2ecf20Sopenharmony_ci .alert = lm90_alert, 20008c2ecf20Sopenharmony_ci .id_table = lm90_id, 20018c2ecf20Sopenharmony_ci .detect = lm90_detect, 20028c2ecf20Sopenharmony_ci .address_list = normal_i2c, 20038c2ecf20Sopenharmony_ci}; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cimodule_i2c_driver(lm90_driver); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); 20088c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LM90/ADM1032 driver"); 20098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2010