18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lm75.c - Part of lm_sensors, Linux kernel modules for hardware 48c2ecf20Sopenharmony_ci * monitoring 58c2ecf20Sopenharmony_ci * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 148c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/util_macros.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 218c2ecf20Sopenharmony_ci#include "lm75.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * This driver handles the LM75 and compatible digital temperature sensors. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cienum lm75_type { /* keep sorted in alphabetical order */ 288c2ecf20Sopenharmony_ci adt75, 298c2ecf20Sopenharmony_ci ds1775, 308c2ecf20Sopenharmony_ci ds75, 318c2ecf20Sopenharmony_ci ds7505, 328c2ecf20Sopenharmony_ci g751, 338c2ecf20Sopenharmony_ci lm75, 348c2ecf20Sopenharmony_ci lm75a, 358c2ecf20Sopenharmony_ci lm75b, 368c2ecf20Sopenharmony_ci max6625, 378c2ecf20Sopenharmony_ci max6626, 388c2ecf20Sopenharmony_ci max31725, 398c2ecf20Sopenharmony_ci mcp980x, 408c2ecf20Sopenharmony_ci pct2075, 418c2ecf20Sopenharmony_ci stds75, 428c2ecf20Sopenharmony_ci stlm75, 438c2ecf20Sopenharmony_ci tcn75, 448c2ecf20Sopenharmony_ci tmp100, 458c2ecf20Sopenharmony_ci tmp101, 468c2ecf20Sopenharmony_ci tmp105, 478c2ecf20Sopenharmony_ci tmp112, 488c2ecf20Sopenharmony_ci tmp175, 498c2ecf20Sopenharmony_ci tmp275, 508c2ecf20Sopenharmony_ci tmp75, 518c2ecf20Sopenharmony_ci tmp75b, 528c2ecf20Sopenharmony_ci tmp75c, 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * struct lm75_params - lm75 configuration parameters. 578c2ecf20Sopenharmony_ci * @set_mask: Bits to set in configuration register when configuring 588c2ecf20Sopenharmony_ci * the chip. 598c2ecf20Sopenharmony_ci * @clr_mask: Bits to clear in configuration register when configuring 608c2ecf20Sopenharmony_ci * the chip. 618c2ecf20Sopenharmony_ci * @default_resolution: Default number of bits to represent the temperature 628c2ecf20Sopenharmony_ci * value. 638c2ecf20Sopenharmony_ci * @resolution_limits: Limit register resolution. Optional. Should be set if 648c2ecf20Sopenharmony_ci * the resolution of limit registers does not match the 658c2ecf20Sopenharmony_ci * resolution of the temperature register. 668c2ecf20Sopenharmony_ci * @resolutions: List of resolutions associated with sample times. 678c2ecf20Sopenharmony_ci * Optional. Should be set if num_sample_times is larger 688c2ecf20Sopenharmony_ci * than 1, and if the resolution changes with sample times. 698c2ecf20Sopenharmony_ci * If set, number of entries must match num_sample_times. 708c2ecf20Sopenharmony_ci * @default_sample_time:Sample time to be set by default. 718c2ecf20Sopenharmony_ci * @num_sample_times: Number of possible sample times to be set. Optional. 728c2ecf20Sopenharmony_ci * Should be set if the number of sample times is larger 738c2ecf20Sopenharmony_ci * than one. 748c2ecf20Sopenharmony_ci * @sample_times: All the possible sample times to be set. Mandatory if 758c2ecf20Sopenharmony_ci * num_sample_times is larger than 1. If set, number of 768c2ecf20Sopenharmony_ci * entries must match num_sample_times. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct lm75_params { 808c2ecf20Sopenharmony_ci u8 set_mask; 818c2ecf20Sopenharmony_ci u8 clr_mask; 828c2ecf20Sopenharmony_ci u8 default_resolution; 838c2ecf20Sopenharmony_ci u8 resolution_limits; 848c2ecf20Sopenharmony_ci const u8 *resolutions; 858c2ecf20Sopenharmony_ci unsigned int default_sample_time; 868c2ecf20Sopenharmony_ci u8 num_sample_times; 878c2ecf20Sopenharmony_ci const unsigned int *sample_times; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Addresses scanned */ 918c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 928c2ecf20Sopenharmony_ci 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* The LM75 registers */ 958c2ecf20Sopenharmony_ci#define LM75_REG_TEMP 0x00 968c2ecf20Sopenharmony_ci#define LM75_REG_CONF 0x01 978c2ecf20Sopenharmony_ci#define LM75_REG_HYST 0x02 988c2ecf20Sopenharmony_ci#define LM75_REG_MAX 0x03 998c2ecf20Sopenharmony_ci#define PCT2075_REG_IDLE 0x04 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* Each client has this additional data */ 1028c2ecf20Sopenharmony_cistruct lm75_data { 1038c2ecf20Sopenharmony_ci struct i2c_client *client; 1048c2ecf20Sopenharmony_ci struct regmap *regmap; 1058c2ecf20Sopenharmony_ci struct regulator *vs; 1068c2ecf20Sopenharmony_ci u8 orig_conf; 1078c2ecf20Sopenharmony_ci u8 current_conf; 1088c2ecf20Sopenharmony_ci u8 resolution; /* In bits, 9 to 16 */ 1098c2ecf20Sopenharmony_ci unsigned int sample_time; /* In ms */ 1108c2ecf20Sopenharmony_ci enum lm75_type kind; 1118c2ecf20Sopenharmony_ci const struct lm75_params *params; 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/*-----------------------------------------------------------------------*/ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 }; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define LM75_SAMPLE_CLEAR_MASK (3 << 5) 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* The structure below stores the configuration values of the supported devices. 1218c2ecf20Sopenharmony_ci * In case of being supported multiple configurations, the default one must 1228c2ecf20Sopenharmony_ci * always be the first element of the array 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistatic const struct lm75_params device_params[] = { 1258c2ecf20Sopenharmony_ci [adt75] = { 1268c2ecf20Sopenharmony_ci .clr_mask = 1 << 5, /* not one-shot mode */ 1278c2ecf20Sopenharmony_ci .default_resolution = 12, 1288c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 10, 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci [ds1775] = { 1318c2ecf20Sopenharmony_ci .clr_mask = 3 << 5, 1328c2ecf20Sopenharmony_ci .set_mask = 2 << 5, /* 11-bit mode */ 1338c2ecf20Sopenharmony_ci .default_resolution = 11, 1348c2ecf20Sopenharmony_ci .default_sample_time = 500, 1358c2ecf20Sopenharmony_ci .num_sample_times = 4, 1368c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 125, 250, 500, 1000 }, 1378c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci [ds75] = { 1408c2ecf20Sopenharmony_ci .clr_mask = 3 << 5, 1418c2ecf20Sopenharmony_ci .set_mask = 2 << 5, /* 11-bit mode */ 1428c2ecf20Sopenharmony_ci .default_resolution = 11, 1438c2ecf20Sopenharmony_ci .default_sample_time = 600, 1448c2ecf20Sopenharmony_ci .num_sample_times = 4, 1458c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, 1468c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci [stds75] = { 1498c2ecf20Sopenharmony_ci .clr_mask = 3 << 5, 1508c2ecf20Sopenharmony_ci .set_mask = 2 << 5, /* 11-bit mode */ 1518c2ecf20Sopenharmony_ci .default_resolution = 11, 1528c2ecf20Sopenharmony_ci .default_sample_time = 600, 1538c2ecf20Sopenharmony_ci .num_sample_times = 4, 1548c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, 1558c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 1568c2ecf20Sopenharmony_ci }, 1578c2ecf20Sopenharmony_ci [stlm75] = { 1588c2ecf20Sopenharmony_ci .default_resolution = 9, 1598c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 6, 1608c2ecf20Sopenharmony_ci }, 1618c2ecf20Sopenharmony_ci [ds7505] = { 1628c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode*/ 1638c2ecf20Sopenharmony_ci .default_resolution = 12, 1648c2ecf20Sopenharmony_ci .default_sample_time = 200, 1658c2ecf20Sopenharmony_ci .num_sample_times = 4, 1668c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 25, 50, 100, 200 }, 1678c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 1688c2ecf20Sopenharmony_ci }, 1698c2ecf20Sopenharmony_ci [g751] = { 1708c2ecf20Sopenharmony_ci .default_resolution = 9, 1718c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 10, 1728c2ecf20Sopenharmony_ci }, 1738c2ecf20Sopenharmony_ci [lm75] = { 1748c2ecf20Sopenharmony_ci .default_resolution = 9, 1758c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 10, 1768c2ecf20Sopenharmony_ci }, 1778c2ecf20Sopenharmony_ci [lm75a] = { 1788c2ecf20Sopenharmony_ci .default_resolution = 9, 1798c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 10, 1808c2ecf20Sopenharmony_ci }, 1818c2ecf20Sopenharmony_ci [lm75b] = { 1828c2ecf20Sopenharmony_ci .default_resolution = 11, 1838c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 10, 1848c2ecf20Sopenharmony_ci }, 1858c2ecf20Sopenharmony_ci [max6625] = { 1868c2ecf20Sopenharmony_ci .default_resolution = 9, 1878c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 7, 1888c2ecf20Sopenharmony_ci }, 1898c2ecf20Sopenharmony_ci [max6626] = { 1908c2ecf20Sopenharmony_ci .default_resolution = 12, 1918c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 7, 1928c2ecf20Sopenharmony_ci .resolution_limits = 9, 1938c2ecf20Sopenharmony_ci }, 1948c2ecf20Sopenharmony_ci [max31725] = { 1958c2ecf20Sopenharmony_ci .default_resolution = 16, 1968c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 20, 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci [tcn75] = { 1998c2ecf20Sopenharmony_ci .default_resolution = 9, 2008c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 18, 2018c2ecf20Sopenharmony_ci }, 2028c2ecf20Sopenharmony_ci [pct2075] = { 2038c2ecf20Sopenharmony_ci .default_resolution = 11, 2048c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 10, 2058c2ecf20Sopenharmony_ci .num_sample_times = 31, 2068c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600, 2078c2ecf20Sopenharmony_ci 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 2088c2ecf20Sopenharmony_ci 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2098c2ecf20Sopenharmony_ci 2800, 2900, 3000, 3100 }, 2108c2ecf20Sopenharmony_ci }, 2118c2ecf20Sopenharmony_ci [mcp980x] = { 2128c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2138c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode */ 2148c2ecf20Sopenharmony_ci .default_resolution = 12, 2158c2ecf20Sopenharmony_ci .resolution_limits = 9, 2168c2ecf20Sopenharmony_ci .default_sample_time = 240, 2178c2ecf20Sopenharmony_ci .num_sample_times = 4, 2188c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 30, 60, 120, 240 }, 2198c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2208c2ecf20Sopenharmony_ci }, 2218c2ecf20Sopenharmony_ci [tmp100] = { 2228c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2238c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode */ 2248c2ecf20Sopenharmony_ci .default_resolution = 12, 2258c2ecf20Sopenharmony_ci .default_sample_time = 320, 2268c2ecf20Sopenharmony_ci .num_sample_times = 4, 2278c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 40, 80, 160, 320 }, 2288c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2298c2ecf20Sopenharmony_ci }, 2308c2ecf20Sopenharmony_ci [tmp101] = { 2318c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2328c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode */ 2338c2ecf20Sopenharmony_ci .default_resolution = 12, 2348c2ecf20Sopenharmony_ci .default_sample_time = 320, 2358c2ecf20Sopenharmony_ci .num_sample_times = 4, 2368c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 40, 80, 160, 320 }, 2378c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2388c2ecf20Sopenharmony_ci }, 2398c2ecf20Sopenharmony_ci [tmp105] = { 2408c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2418c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode*/ 2428c2ecf20Sopenharmony_ci .default_resolution = 12, 2438c2ecf20Sopenharmony_ci .default_sample_time = 220, 2448c2ecf20Sopenharmony_ci .num_sample_times = 4, 2458c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 28, 55, 110, 220 }, 2468c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2478c2ecf20Sopenharmony_ci }, 2488c2ecf20Sopenharmony_ci [tmp112] = { 2498c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 8 samples / second */ 2508c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* no one-shot mode*/ 2518c2ecf20Sopenharmony_ci .default_resolution = 12, 2528c2ecf20Sopenharmony_ci .default_sample_time = 125, 2538c2ecf20Sopenharmony_ci .num_sample_times = 4, 2548c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, 2558c2ecf20Sopenharmony_ci }, 2568c2ecf20Sopenharmony_ci [tmp175] = { 2578c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2588c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode*/ 2598c2ecf20Sopenharmony_ci .default_resolution = 12, 2608c2ecf20Sopenharmony_ci .default_sample_time = 220, 2618c2ecf20Sopenharmony_ci .num_sample_times = 4, 2628c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 28, 55, 110, 220 }, 2638c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci [tmp275] = { 2668c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2678c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode*/ 2688c2ecf20Sopenharmony_ci .default_resolution = 12, 2698c2ecf20Sopenharmony_ci .default_sample_time = 220, 2708c2ecf20Sopenharmony_ci .num_sample_times = 4, 2718c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 28, 55, 110, 220 }, 2728c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2738c2ecf20Sopenharmony_ci }, 2748c2ecf20Sopenharmony_ci [tmp75] = { 2758c2ecf20Sopenharmony_ci .set_mask = 3 << 5, /* 12-bit mode */ 2768c2ecf20Sopenharmony_ci .clr_mask = 1 << 7, /* not one-shot mode*/ 2778c2ecf20Sopenharmony_ci .default_resolution = 12, 2788c2ecf20Sopenharmony_ci .default_sample_time = 220, 2798c2ecf20Sopenharmony_ci .num_sample_times = 4, 2808c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ 28, 55, 110, 220 }, 2818c2ecf20Sopenharmony_ci .resolutions = (u8 []) {9, 10, 11, 12 }, 2828c2ecf20Sopenharmony_ci }, 2838c2ecf20Sopenharmony_ci [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */ 2848c2ecf20Sopenharmony_ci .clr_mask = 1 << 7 | 3 << 5, 2858c2ecf20Sopenharmony_ci .default_resolution = 12, 2868c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 37, 2878c2ecf20Sopenharmony_ci .sample_times = (unsigned int []){ MSEC_PER_SEC / 37, 2888c2ecf20Sopenharmony_ci MSEC_PER_SEC / 18, 2898c2ecf20Sopenharmony_ci MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 }, 2908c2ecf20Sopenharmony_ci .num_sample_times = 4, 2918c2ecf20Sopenharmony_ci }, 2928c2ecf20Sopenharmony_ci [tmp75c] = { 2938c2ecf20Sopenharmony_ci .clr_mask = 1 << 5, /*not one-shot mode*/ 2948c2ecf20Sopenharmony_ci .default_resolution = 12, 2958c2ecf20Sopenharmony_ci .default_sample_time = MSEC_PER_SEC / 12, 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic inline long lm75_reg_to_mc(s16 temp, u8 resolution) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int lm75_write_config(struct lm75_data *data, u8 set_mask, 3058c2ecf20Sopenharmony_ci u8 clr_mask) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci u8 value; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci clr_mask |= LM75_SHUTDOWN; 3108c2ecf20Sopenharmony_ci value = data->current_conf & ~clr_mask; 3118c2ecf20Sopenharmony_ci value |= set_mask; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (data->current_conf != value) { 3148c2ecf20Sopenharmony_ci s32 err; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF, 3178c2ecf20Sopenharmony_ci value); 3188c2ecf20Sopenharmony_ci if (err) 3198c2ecf20Sopenharmony_ci return err; 3208c2ecf20Sopenharmony_ci data->current_conf = value; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int lm75_read(struct device *dev, enum hwmon_sensor_types type, 3268c2ecf20Sopenharmony_ci u32 attr, int channel, long *val) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct lm75_data *data = dev_get_drvdata(dev); 3298c2ecf20Sopenharmony_ci unsigned int regval; 3308c2ecf20Sopenharmony_ci int err, reg; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci switch (type) { 3338c2ecf20Sopenharmony_ci case hwmon_chip: 3348c2ecf20Sopenharmony_ci switch (attr) { 3358c2ecf20Sopenharmony_ci case hwmon_chip_update_interval: 3368c2ecf20Sopenharmony_ci *val = data->sample_time; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci default: 3398c2ecf20Sopenharmony_ci return -EINVAL; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci case hwmon_temp: 3438c2ecf20Sopenharmony_ci switch (attr) { 3448c2ecf20Sopenharmony_ci case hwmon_temp_input: 3458c2ecf20Sopenharmony_ci reg = LM75_REG_TEMP; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci case hwmon_temp_max: 3488c2ecf20Sopenharmony_ci reg = LM75_REG_MAX; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case hwmon_temp_max_hyst: 3518c2ecf20Sopenharmony_ci reg = LM75_REG_HYST; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci default: 3548c2ecf20Sopenharmony_ci return -EINVAL; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, reg, ®val); 3578c2ecf20Sopenharmony_ci if (err < 0) 3588c2ecf20Sopenharmony_ci return err; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci *val = lm75_reg_to_mc(regval, data->resolution); 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci default: 3638c2ecf20Sopenharmony_ci return -EINVAL; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int lm75_write_temp(struct device *dev, u32 attr, long temp) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct lm75_data *data = dev_get_drvdata(dev); 3718c2ecf20Sopenharmony_ci u8 resolution; 3728c2ecf20Sopenharmony_ci int reg; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci switch (attr) { 3758c2ecf20Sopenharmony_ci case hwmon_temp_max: 3768c2ecf20Sopenharmony_ci reg = LM75_REG_MAX; 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci case hwmon_temp_max_hyst: 3798c2ecf20Sopenharmony_ci reg = LM75_REG_HYST; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci default: 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * Resolution of limit registers is assumed to be the same as the 3878c2ecf20Sopenharmony_ci * temperature input register resolution unless given explicitly. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci if (data->params->resolution_limits) 3908c2ecf20Sopenharmony_ci resolution = data->params->resolution_limits; 3918c2ecf20Sopenharmony_ci else 3928c2ecf20Sopenharmony_ci resolution = data->resolution; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); 3958c2ecf20Sopenharmony_ci temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), 3968c2ecf20Sopenharmony_ci 1000) << (16 - resolution); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return regmap_write(data->regmap, reg, (u16)temp); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int lm75_update_interval(struct device *dev, long val) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct lm75_data *data = dev_get_drvdata(dev); 4048c2ecf20Sopenharmony_ci unsigned int reg; 4058c2ecf20Sopenharmony_ci u8 index; 4068c2ecf20Sopenharmony_ci s32 err; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci index = find_closest(val, data->params->sample_times, 4098c2ecf20Sopenharmony_ci (int)data->params->num_sample_times); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci switch (data->kind) { 4128c2ecf20Sopenharmony_ci default: 4138c2ecf20Sopenharmony_ci err = lm75_write_config(data, lm75_sample_set_masks[index], 4148c2ecf20Sopenharmony_ci LM75_SAMPLE_CLEAR_MASK); 4158c2ecf20Sopenharmony_ci if (err) 4168c2ecf20Sopenharmony_ci return err; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci data->sample_time = data->params->sample_times[index]; 4198c2ecf20Sopenharmony_ci if (data->params->resolutions) 4208c2ecf20Sopenharmony_ci data->resolution = data->params->resolutions[index]; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci case tmp112: 4238c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, LM75_REG_CONF, ®); 4248c2ecf20Sopenharmony_ci if (err < 0) 4258c2ecf20Sopenharmony_ci return err; 4268c2ecf20Sopenharmony_ci reg &= ~0x00c0; 4278c2ecf20Sopenharmony_ci reg |= (3 - index) << 6; 4288c2ecf20Sopenharmony_ci err = regmap_write(data->regmap, LM75_REG_CONF, reg); 4298c2ecf20Sopenharmony_ci if (err < 0) 4308c2ecf20Sopenharmony_ci return err; 4318c2ecf20Sopenharmony_ci data->sample_time = data->params->sample_times[index]; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci case pct2075: 4348c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, 4358c2ecf20Sopenharmony_ci index + 1); 4368c2ecf20Sopenharmony_ci if (err) 4378c2ecf20Sopenharmony_ci return err; 4388c2ecf20Sopenharmony_ci data->sample_time = data->params->sample_times[index]; 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int lm75_write_chip(struct device *dev, u32 attr, long val) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci switch (attr) { 4478c2ecf20Sopenharmony_ci case hwmon_chip_update_interval: 4488c2ecf20Sopenharmony_ci return lm75_update_interval(dev, val); 4498c2ecf20Sopenharmony_ci default: 4508c2ecf20Sopenharmony_ci return -EINVAL; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int lm75_write(struct device *dev, enum hwmon_sensor_types type, 4568c2ecf20Sopenharmony_ci u32 attr, int channel, long val) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci switch (type) { 4598c2ecf20Sopenharmony_ci case hwmon_chip: 4608c2ecf20Sopenharmony_ci return lm75_write_chip(dev, attr, val); 4618c2ecf20Sopenharmony_ci case hwmon_temp: 4628c2ecf20Sopenharmony_ci return lm75_write_temp(dev, attr, val); 4638c2ecf20Sopenharmony_ci default: 4648c2ecf20Sopenharmony_ci return -EINVAL; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, 4708c2ecf20Sopenharmony_ci u32 attr, int channel) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci const struct lm75_data *config_data = data; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci switch (type) { 4758c2ecf20Sopenharmony_ci case hwmon_chip: 4768c2ecf20Sopenharmony_ci switch (attr) { 4778c2ecf20Sopenharmony_ci case hwmon_chip_update_interval: 4788c2ecf20Sopenharmony_ci if (config_data->params->num_sample_times > 1) 4798c2ecf20Sopenharmony_ci return 0644; 4808c2ecf20Sopenharmony_ci return 0444; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case hwmon_temp: 4848c2ecf20Sopenharmony_ci switch (attr) { 4858c2ecf20Sopenharmony_ci case hwmon_temp_input: 4868c2ecf20Sopenharmony_ci return 0444; 4878c2ecf20Sopenharmony_ci case hwmon_temp_max: 4888c2ecf20Sopenharmony_ci case hwmon_temp_max_hyst: 4898c2ecf20Sopenharmony_ci return 0644; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci default: 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *lm75_info[] = { 4998c2ecf20Sopenharmony_ci HWMON_CHANNEL_INFO(chip, 5008c2ecf20Sopenharmony_ci HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), 5018c2ecf20Sopenharmony_ci HWMON_CHANNEL_INFO(temp, 5028c2ecf20Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), 5038c2ecf20Sopenharmony_ci NULL 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic const struct hwmon_ops lm75_hwmon_ops = { 5078c2ecf20Sopenharmony_ci .is_visible = lm75_is_visible, 5088c2ecf20Sopenharmony_ci .read = lm75_read, 5098c2ecf20Sopenharmony_ci .write = lm75_write, 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info lm75_chip_info = { 5138c2ecf20Sopenharmony_ci .ops = &lm75_hwmon_ops, 5148c2ecf20Sopenharmony_ci .info = lm75_info, 5158c2ecf20Sopenharmony_ci}; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci return reg != LM75_REG_TEMP; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic const struct regmap_config lm75_regmap_config = { 5288c2ecf20Sopenharmony_ci .reg_bits = 8, 5298c2ecf20Sopenharmony_ci .val_bits = 16, 5308c2ecf20Sopenharmony_ci .max_register = PCT2075_REG_IDLE, 5318c2ecf20Sopenharmony_ci .writeable_reg = lm75_is_writeable_reg, 5328c2ecf20Sopenharmony_ci .volatile_reg = lm75_is_volatile_reg, 5338c2ecf20Sopenharmony_ci .val_format_endian = REGMAP_ENDIAN_BIG, 5348c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 5358c2ecf20Sopenharmony_ci .use_single_read = true, 5368c2ecf20Sopenharmony_ci .use_single_write = true, 5378c2ecf20Sopenharmony_ci}; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic void lm75_disable_regulator(void *data) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct lm75_data *lm75 = data; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci regulator_disable(lm75->vs); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void lm75_remove(void *data) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct lm75_data *lm75 = data; 5498c2ecf20Sopenharmony_ci struct i2c_client *client = lm75->client; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm75_ids[]; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int lm75_probe(struct i2c_client *client) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 5598c2ecf20Sopenharmony_ci struct device *hwmon_dev; 5608c2ecf20Sopenharmony_ci struct lm75_data *data; 5618c2ecf20Sopenharmony_ci int status, err; 5628c2ecf20Sopenharmony_ci enum lm75_type kind; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (client->dev.of_node) 5658c2ecf20Sopenharmony_ci kind = (enum lm75_type)of_device_get_match_data(&client->dev); 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci kind = i2c_match_id(lm75_ids, client)->driver_data; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, 5708c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) 5718c2ecf20Sopenharmony_ci return -EIO; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); 5748c2ecf20Sopenharmony_ci if (!data) 5758c2ecf20Sopenharmony_ci return -ENOMEM; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci data->client = client; 5788c2ecf20Sopenharmony_ci data->kind = kind; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci data->vs = devm_regulator_get(dev, "vs"); 5818c2ecf20Sopenharmony_ci if (IS_ERR(data->vs)) 5828c2ecf20Sopenharmony_ci return PTR_ERR(data->vs); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); 5858c2ecf20Sopenharmony_ci if (IS_ERR(data->regmap)) 5868c2ecf20Sopenharmony_ci return PTR_ERR(data->regmap); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. 5898c2ecf20Sopenharmony_ci * Then tweak to be more precise when appropriate. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci data->params = &device_params[data->kind]; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* Save default sample time and resolution*/ 5958c2ecf20Sopenharmony_ci data->sample_time = data->params->default_sample_time; 5968c2ecf20Sopenharmony_ci data->resolution = data->params->default_resolution; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Enable the power */ 5998c2ecf20Sopenharmony_ci err = regulator_enable(data->vs); 6008c2ecf20Sopenharmony_ci if (err) { 6018c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable regulator: %d\n", err); 6028c2ecf20Sopenharmony_ci return err; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); 6068c2ecf20Sopenharmony_ci if (err) 6078c2ecf20Sopenharmony_ci return err; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Cache original configuration */ 6108c2ecf20Sopenharmony_ci status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); 6118c2ecf20Sopenharmony_ci if (status < 0) { 6128c2ecf20Sopenharmony_ci dev_dbg(dev, "Can't read config? %d\n", status); 6138c2ecf20Sopenharmony_ci return status; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci data->orig_conf = status; 6168c2ecf20Sopenharmony_ci data->current_conf = status; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci err = lm75_write_config(data, data->params->set_mask, 6198c2ecf20Sopenharmony_ci data->params->clr_mask); 6208c2ecf20Sopenharmony_ci if (err) 6218c2ecf20Sopenharmony_ci return err; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(dev, lm75_remove, data); 6248c2ecf20Sopenharmony_ci if (err) 6258c2ecf20Sopenharmony_ci return err; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 6288c2ecf20Sopenharmony_ci data, &lm75_chip_info, 6298c2ecf20Sopenharmony_ci NULL); 6308c2ecf20Sopenharmony_ci if (IS_ERR(hwmon_dev)) 6318c2ecf20Sopenharmony_ci return PTR_ERR(hwmon_dev); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm75_ids[] = { 6398c2ecf20Sopenharmony_ci { "adt75", adt75, }, 6408c2ecf20Sopenharmony_ci { "ds1775", ds1775, }, 6418c2ecf20Sopenharmony_ci { "ds75", ds75, }, 6428c2ecf20Sopenharmony_ci { "ds7505", ds7505, }, 6438c2ecf20Sopenharmony_ci { "g751", g751, }, 6448c2ecf20Sopenharmony_ci { "lm75", lm75, }, 6458c2ecf20Sopenharmony_ci { "lm75a", lm75a, }, 6468c2ecf20Sopenharmony_ci { "lm75b", lm75b, }, 6478c2ecf20Sopenharmony_ci { "max6625", max6625, }, 6488c2ecf20Sopenharmony_ci { "max6626", max6626, }, 6498c2ecf20Sopenharmony_ci { "max31725", max31725, }, 6508c2ecf20Sopenharmony_ci { "max31726", max31725, }, 6518c2ecf20Sopenharmony_ci { "mcp980x", mcp980x, }, 6528c2ecf20Sopenharmony_ci { "pct2075", pct2075, }, 6538c2ecf20Sopenharmony_ci { "stds75", stds75, }, 6548c2ecf20Sopenharmony_ci { "stlm75", stlm75, }, 6558c2ecf20Sopenharmony_ci { "tcn75", tcn75, }, 6568c2ecf20Sopenharmony_ci { "tmp100", tmp100, }, 6578c2ecf20Sopenharmony_ci { "tmp101", tmp101, }, 6588c2ecf20Sopenharmony_ci { "tmp105", tmp105, }, 6598c2ecf20Sopenharmony_ci { "tmp112", tmp112, }, 6608c2ecf20Sopenharmony_ci { "tmp175", tmp175, }, 6618c2ecf20Sopenharmony_ci { "tmp275", tmp275, }, 6628c2ecf20Sopenharmony_ci { "tmp75", tmp75, }, 6638c2ecf20Sopenharmony_ci { "tmp75b", tmp75b, }, 6648c2ecf20Sopenharmony_ci { "tmp75c", tmp75c, }, 6658c2ecf20Sopenharmony_ci { /* LIST END */ } 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm75_ids); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused lm75_of_match[] = { 6708c2ecf20Sopenharmony_ci { 6718c2ecf20Sopenharmony_ci .compatible = "adi,adt75", 6728c2ecf20Sopenharmony_ci .data = (void *)adt75 6738c2ecf20Sopenharmony_ci }, 6748c2ecf20Sopenharmony_ci { 6758c2ecf20Sopenharmony_ci .compatible = "dallas,ds1775", 6768c2ecf20Sopenharmony_ci .data = (void *)ds1775 6778c2ecf20Sopenharmony_ci }, 6788c2ecf20Sopenharmony_ci { 6798c2ecf20Sopenharmony_ci .compatible = "dallas,ds75", 6808c2ecf20Sopenharmony_ci .data = (void *)ds75 6818c2ecf20Sopenharmony_ci }, 6828c2ecf20Sopenharmony_ci { 6838c2ecf20Sopenharmony_ci .compatible = "dallas,ds7505", 6848c2ecf20Sopenharmony_ci .data = (void *)ds7505 6858c2ecf20Sopenharmony_ci }, 6868c2ecf20Sopenharmony_ci { 6878c2ecf20Sopenharmony_ci .compatible = "gmt,g751", 6888c2ecf20Sopenharmony_ci .data = (void *)g751 6898c2ecf20Sopenharmony_ci }, 6908c2ecf20Sopenharmony_ci { 6918c2ecf20Sopenharmony_ci .compatible = "national,lm75", 6928c2ecf20Sopenharmony_ci .data = (void *)lm75 6938c2ecf20Sopenharmony_ci }, 6948c2ecf20Sopenharmony_ci { 6958c2ecf20Sopenharmony_ci .compatible = "national,lm75a", 6968c2ecf20Sopenharmony_ci .data = (void *)lm75a 6978c2ecf20Sopenharmony_ci }, 6988c2ecf20Sopenharmony_ci { 6998c2ecf20Sopenharmony_ci .compatible = "national,lm75b", 7008c2ecf20Sopenharmony_ci .data = (void *)lm75b 7018c2ecf20Sopenharmony_ci }, 7028c2ecf20Sopenharmony_ci { 7038c2ecf20Sopenharmony_ci .compatible = "maxim,max6625", 7048c2ecf20Sopenharmony_ci .data = (void *)max6625 7058c2ecf20Sopenharmony_ci }, 7068c2ecf20Sopenharmony_ci { 7078c2ecf20Sopenharmony_ci .compatible = "maxim,max6626", 7088c2ecf20Sopenharmony_ci .data = (void *)max6626 7098c2ecf20Sopenharmony_ci }, 7108c2ecf20Sopenharmony_ci { 7118c2ecf20Sopenharmony_ci .compatible = "maxim,max31725", 7128c2ecf20Sopenharmony_ci .data = (void *)max31725 7138c2ecf20Sopenharmony_ci }, 7148c2ecf20Sopenharmony_ci { 7158c2ecf20Sopenharmony_ci .compatible = "maxim,max31726", 7168c2ecf20Sopenharmony_ci .data = (void *)max31725 7178c2ecf20Sopenharmony_ci }, 7188c2ecf20Sopenharmony_ci { 7198c2ecf20Sopenharmony_ci .compatible = "maxim,mcp980x", 7208c2ecf20Sopenharmony_ci .data = (void *)mcp980x 7218c2ecf20Sopenharmony_ci }, 7228c2ecf20Sopenharmony_ci { 7238c2ecf20Sopenharmony_ci .compatible = "nxp,pct2075", 7248c2ecf20Sopenharmony_ci .data = (void *)pct2075 7258c2ecf20Sopenharmony_ci }, 7268c2ecf20Sopenharmony_ci { 7278c2ecf20Sopenharmony_ci .compatible = "st,stds75", 7288c2ecf20Sopenharmony_ci .data = (void *)stds75 7298c2ecf20Sopenharmony_ci }, 7308c2ecf20Sopenharmony_ci { 7318c2ecf20Sopenharmony_ci .compatible = "st,stlm75", 7328c2ecf20Sopenharmony_ci .data = (void *)stlm75 7338c2ecf20Sopenharmony_ci }, 7348c2ecf20Sopenharmony_ci { 7358c2ecf20Sopenharmony_ci .compatible = "microchip,tcn75", 7368c2ecf20Sopenharmony_ci .data = (void *)tcn75 7378c2ecf20Sopenharmony_ci }, 7388c2ecf20Sopenharmony_ci { 7398c2ecf20Sopenharmony_ci .compatible = "ti,tmp100", 7408c2ecf20Sopenharmony_ci .data = (void *)tmp100 7418c2ecf20Sopenharmony_ci }, 7428c2ecf20Sopenharmony_ci { 7438c2ecf20Sopenharmony_ci .compatible = "ti,tmp101", 7448c2ecf20Sopenharmony_ci .data = (void *)tmp101 7458c2ecf20Sopenharmony_ci }, 7468c2ecf20Sopenharmony_ci { 7478c2ecf20Sopenharmony_ci .compatible = "ti,tmp105", 7488c2ecf20Sopenharmony_ci .data = (void *)tmp105 7498c2ecf20Sopenharmony_ci }, 7508c2ecf20Sopenharmony_ci { 7518c2ecf20Sopenharmony_ci .compatible = "ti,tmp112", 7528c2ecf20Sopenharmony_ci .data = (void *)tmp112 7538c2ecf20Sopenharmony_ci }, 7548c2ecf20Sopenharmony_ci { 7558c2ecf20Sopenharmony_ci .compatible = "ti,tmp175", 7568c2ecf20Sopenharmony_ci .data = (void *)tmp175 7578c2ecf20Sopenharmony_ci }, 7588c2ecf20Sopenharmony_ci { 7598c2ecf20Sopenharmony_ci .compatible = "ti,tmp275", 7608c2ecf20Sopenharmony_ci .data = (void *)tmp275 7618c2ecf20Sopenharmony_ci }, 7628c2ecf20Sopenharmony_ci { 7638c2ecf20Sopenharmony_ci .compatible = "ti,tmp75", 7648c2ecf20Sopenharmony_ci .data = (void *)tmp75 7658c2ecf20Sopenharmony_ci }, 7668c2ecf20Sopenharmony_ci { 7678c2ecf20Sopenharmony_ci .compatible = "ti,tmp75b", 7688c2ecf20Sopenharmony_ci .data = (void *)tmp75b 7698c2ecf20Sopenharmony_ci }, 7708c2ecf20Sopenharmony_ci { 7718c2ecf20Sopenharmony_ci .compatible = "ti,tmp75c", 7728c2ecf20Sopenharmony_ci .data = (void *)tmp75c 7738c2ecf20Sopenharmony_ci }, 7748c2ecf20Sopenharmony_ci { }, 7758c2ecf20Sopenharmony_ci}; 7768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lm75_of_match); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci#define LM75A_ID 0xA1 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 7818c2ecf20Sopenharmony_cistatic int lm75_detect(struct i2c_client *new_client, 7828c2ecf20Sopenharmony_ci struct i2c_board_info *info) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = new_client->adapter; 7858c2ecf20Sopenharmony_ci int i; 7868c2ecf20Sopenharmony_ci int conf, hyst, os; 7878c2ecf20Sopenharmony_ci bool is_lm75a = 0; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | 7908c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA)) 7918c2ecf20Sopenharmony_ci return -ENODEV; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * Now, we do the remaining detection. There is no identification- 7958c2ecf20Sopenharmony_ci * dedicated register so we have to rely on several tricks: 7968c2ecf20Sopenharmony_ci * unused bits, registers cycling over 8-address boundaries, 7978c2ecf20Sopenharmony_ci * addresses 0x04-0x07 returning the last read value. 7988c2ecf20Sopenharmony_ci * The cycling+unused addresses combination is not tested, 7998c2ecf20Sopenharmony_ci * since it would significantly slow the detection down and would 8008c2ecf20Sopenharmony_ci * hardly add any value. 8018c2ecf20Sopenharmony_ci * 8028c2ecf20Sopenharmony_ci * The National Semiconductor LM75A is different than earlier 8038c2ecf20Sopenharmony_ci * LM75s. It has an ID byte of 0xaX (where X is the chip 8048c2ecf20Sopenharmony_ci * revision, with 1 being the only revision in existence) in 8058c2ecf20Sopenharmony_ci * register 7, and unused registers return 0xff rather than the 8068c2ecf20Sopenharmony_ci * last read value. 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci * Note that this function only detects the original National 8098c2ecf20Sopenharmony_ci * Semiconductor LM75 and the LM75A. Clones from other vendors 8108c2ecf20Sopenharmony_ci * aren't detected, on purpose, because they are typically never 8118c2ecf20Sopenharmony_ci * found on PC hardware. They are found on embedded designs where 8128c2ecf20Sopenharmony_ci * they can be instantiated explicitly so detection is not needed. 8138c2ecf20Sopenharmony_ci * The absence of identification registers on all these clones 8148c2ecf20Sopenharmony_ci * would make their exhaustive detection very difficult and weak, 8158c2ecf20Sopenharmony_ci * and odds are that the driver would bind to unsupported devices. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* Unused bits */ 8198c2ecf20Sopenharmony_ci conf = i2c_smbus_read_byte_data(new_client, 1); 8208c2ecf20Sopenharmony_ci if (conf & 0xe0) 8218c2ecf20Sopenharmony_ci return -ENODEV; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* First check for LM75A */ 8248c2ecf20Sopenharmony_ci if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { 8258c2ecf20Sopenharmony_ci /* 8268c2ecf20Sopenharmony_ci * LM75A returns 0xff on unused registers so 8278c2ecf20Sopenharmony_ci * just to be sure we check for that too. 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_ci if (i2c_smbus_read_byte_data(new_client, 4) != 0xff 8308c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 5) != 0xff 8318c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 6) != 0xff) 8328c2ecf20Sopenharmony_ci return -ENODEV; 8338c2ecf20Sopenharmony_ci is_lm75a = 1; 8348c2ecf20Sopenharmony_ci hyst = i2c_smbus_read_byte_data(new_client, 2); 8358c2ecf20Sopenharmony_ci os = i2c_smbus_read_byte_data(new_client, 3); 8368c2ecf20Sopenharmony_ci } else { /* Traditional style LM75 detection */ 8378c2ecf20Sopenharmony_ci /* Unused addresses */ 8388c2ecf20Sopenharmony_ci hyst = i2c_smbus_read_byte_data(new_client, 2); 8398c2ecf20Sopenharmony_ci if (i2c_smbus_read_byte_data(new_client, 4) != hyst 8408c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 5) != hyst 8418c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 6) != hyst 8428c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 7) != hyst) 8438c2ecf20Sopenharmony_ci return -ENODEV; 8448c2ecf20Sopenharmony_ci os = i2c_smbus_read_byte_data(new_client, 3); 8458c2ecf20Sopenharmony_ci if (i2c_smbus_read_byte_data(new_client, 4) != os 8468c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 5) != os 8478c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 6) != os 8488c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, 7) != os) 8498c2ecf20Sopenharmony_ci return -ENODEV; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci * It is very unlikely that this is a LM75 if both 8538c2ecf20Sopenharmony_ci * hysteresis and temperature limit registers are 0. 8548c2ecf20Sopenharmony_ci */ 8558c2ecf20Sopenharmony_ci if (hyst == 0 && os == 0) 8568c2ecf20Sopenharmony_ci return -ENODEV; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Addresses cycling */ 8598c2ecf20Sopenharmony_ci for (i = 8; i <= 248; i += 40) { 8608c2ecf20Sopenharmony_ci if (i2c_smbus_read_byte_data(new_client, i + 1) != conf 8618c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, i + 2) != hyst 8628c2ecf20Sopenharmony_ci || i2c_smbus_read_byte_data(new_client, i + 3) != os) 8638c2ecf20Sopenharmony_ci return -ENODEV; 8648c2ecf20Sopenharmony_ci if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) 8658c2ecf20Sopenharmony_ci != LM75A_ID) 8668c2ecf20Sopenharmony_ci return -ENODEV; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 8758c2ecf20Sopenharmony_cistatic int lm75_suspend(struct device *dev) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci int status; 8788c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); 8818c2ecf20Sopenharmony_ci if (status < 0) { 8828c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Can't read config? %d\n", status); 8838c2ecf20Sopenharmony_ci return status; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci status = status | LM75_SHUTDOWN; 8868c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); 8878c2ecf20Sopenharmony_ci return 0; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic int lm75_resume(struct device *dev) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci int status; 8938c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); 8968c2ecf20Sopenharmony_ci if (status < 0) { 8978c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Can't read config? %d\n", status); 8988c2ecf20Sopenharmony_ci return status; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci status = status & ~LM75_SHUTDOWN; 9018c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic const struct dev_pm_ops lm75_dev_pm_ops = { 9068c2ecf20Sopenharmony_ci .suspend = lm75_suspend, 9078c2ecf20Sopenharmony_ci .resume = lm75_resume, 9088c2ecf20Sopenharmony_ci}; 9098c2ecf20Sopenharmony_ci#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops) 9108c2ecf20Sopenharmony_ci#else 9118c2ecf20Sopenharmony_ci#define LM75_DEV_PM_OPS NULL 9128c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic struct i2c_driver lm75_driver = { 9158c2ecf20Sopenharmony_ci .class = I2C_CLASS_HWMON, 9168c2ecf20Sopenharmony_ci .driver = { 9178c2ecf20Sopenharmony_ci .name = "lm75", 9188c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(lm75_of_match), 9198c2ecf20Sopenharmony_ci .pm = LM75_DEV_PM_OPS, 9208c2ecf20Sopenharmony_ci }, 9218c2ecf20Sopenharmony_ci .probe_new = lm75_probe, 9228c2ecf20Sopenharmony_ci .id_table = lm75_ids, 9238c2ecf20Sopenharmony_ci .detect = lm75_detect, 9248c2ecf20Sopenharmony_ci .address_list = normal_i2c, 9258c2ecf20Sopenharmony_ci}; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cimodule_i2c_driver(lm75_driver); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); 9308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LM75 driver"); 9318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 932