162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * A hwmon driver for the Analog Devices ADT7470 462306a36Sopenharmony_ci * Copyright (C) 2007 IBM 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/jiffies.h> 1362306a36Sopenharmony_ci#include <linux/i2c.h> 1462306a36Sopenharmony_ci#include <linux/hwmon.h> 1562306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/mutex.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/log2.h> 2062306a36Sopenharmony_ci#include <linux/kthread.h> 2162306a36Sopenharmony_ci#include <linux/regmap.h> 2262306a36Sopenharmony_ci#include <linux/sched.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/util_macros.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Addresses to scan */ 2762306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* ADT7470 registers */ 3062306a36Sopenharmony_ci#define ADT7470_REG_BASE_ADDR 0x20 3162306a36Sopenharmony_ci#define ADT7470_REG_TEMP_BASE_ADDR 0x20 3262306a36Sopenharmony_ci#define ADT7470_REG_TEMP_MAX_ADDR 0x29 3362306a36Sopenharmony_ci#define ADT7470_REG_FAN_BASE_ADDR 0x2A 3462306a36Sopenharmony_ci#define ADT7470_REG_FAN_MAX_ADDR 0x31 3562306a36Sopenharmony_ci#define ADT7470_REG_PWM_BASE_ADDR 0x32 3662306a36Sopenharmony_ci#define ADT7470_REG_PWM_MAX_ADDR 0x35 3762306a36Sopenharmony_ci#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38 3862306a36Sopenharmony_ci#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B 3962306a36Sopenharmony_ci#define ADT7470_REG_CFG 0x40 4062306a36Sopenharmony_ci#define ADT7470_STRT_MASK 0x01 4162306a36Sopenharmony_ci#define ADT7470_TEST_MASK 0x02 4262306a36Sopenharmony_ci#define ADT7470_FSPD_MASK 0x04 4362306a36Sopenharmony_ci#define ADT7470_T05_STB_MASK 0x80 4462306a36Sopenharmony_ci#define ADT7470_REG_ALARM1 0x41 4562306a36Sopenharmony_ci#define ADT7470_R1T_ALARM 0x01 4662306a36Sopenharmony_ci#define ADT7470_R2T_ALARM 0x02 4762306a36Sopenharmony_ci#define ADT7470_R3T_ALARM 0x04 4862306a36Sopenharmony_ci#define ADT7470_R4T_ALARM 0x08 4962306a36Sopenharmony_ci#define ADT7470_R5T_ALARM 0x10 5062306a36Sopenharmony_ci#define ADT7470_R6T_ALARM 0x20 5162306a36Sopenharmony_ci#define ADT7470_R7T_ALARM 0x40 5262306a36Sopenharmony_ci#define ADT7470_OOL_ALARM 0x80 5362306a36Sopenharmony_ci#define ADT7470_REG_ALARM2 0x42 5462306a36Sopenharmony_ci#define ADT7470_R8T_ALARM 0x01 5562306a36Sopenharmony_ci#define ADT7470_R9T_ALARM 0x02 5662306a36Sopenharmony_ci#define ADT7470_R10T_ALARM 0x04 5762306a36Sopenharmony_ci#define ADT7470_FAN1_ALARM 0x10 5862306a36Sopenharmony_ci#define ADT7470_FAN2_ALARM 0x20 5962306a36Sopenharmony_ci#define ADT7470_FAN3_ALARM 0x40 6062306a36Sopenharmony_ci#define ADT7470_FAN4_ALARM 0x80 6162306a36Sopenharmony_ci#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44 6262306a36Sopenharmony_ci#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57 6362306a36Sopenharmony_ci#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58 6462306a36Sopenharmony_ci#define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F 6562306a36Sopenharmony_ci#define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60 6662306a36Sopenharmony_ci#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67 6762306a36Sopenharmony_ci#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68 6862306a36Sopenharmony_ci#define ADT7470_REG_PWM12_CFG 0x68 6962306a36Sopenharmony_ci#define ADT7470_PWM2_AUTO_MASK 0x40 7062306a36Sopenharmony_ci#define ADT7470_PWM1_AUTO_MASK 0x80 7162306a36Sopenharmony_ci#define ADT7470_PWM_AUTO_MASK 0xC0 7262306a36Sopenharmony_ci#define ADT7470_REG_PWM34_CFG 0x69 7362306a36Sopenharmony_ci#define ADT7470_PWM3_AUTO_MASK 0x40 7462306a36Sopenharmony_ci#define ADT7470_PWM4_AUTO_MASK 0x80 7562306a36Sopenharmony_ci#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A 7662306a36Sopenharmony_ci#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D 7762306a36Sopenharmony_ci#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E 7862306a36Sopenharmony_ci#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71 7962306a36Sopenharmony_ci#define ADT7470_REG_CFG_2 0x74 8062306a36Sopenharmony_ci#define ADT7470_REG_ACOUSTICS12 0x75 8162306a36Sopenharmony_ci#define ADT7470_REG_ACOUSTICS34 0x76 8262306a36Sopenharmony_ci#define ADT7470_REG_DEVICE 0x3D 8362306a36Sopenharmony_ci#define ADT7470_REG_VENDOR 0x3E 8462306a36Sopenharmony_ci#define ADT7470_REG_REVISION 0x3F 8562306a36Sopenharmony_ci#define ADT7470_REG_ALARM1_MASK 0x72 8662306a36Sopenharmony_ci#define ADT7470_REG_ALARM2_MASK 0x73 8762306a36Sopenharmony_ci#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C 8862306a36Sopenharmony_ci#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D 8962306a36Sopenharmony_ci#define ADT7470_REG_MAX_ADDR 0x81 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define ADT7470_TEMP_COUNT 10 9262306a36Sopenharmony_ci#define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x)) 9362306a36Sopenharmony_ci#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2)) 9462306a36Sopenharmony_ci#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \ 9562306a36Sopenharmony_ci ((x) * 2) + 1) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define ADT7470_FAN_COUNT 4 9862306a36Sopenharmony_ci#define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2)) 9962306a36Sopenharmony_ci#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2)) 10062306a36Sopenharmony_ci#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2)) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#define ADT7470_PWM_COUNT 4 10362306a36Sopenharmony_ci#define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x)) 10462306a36Sopenharmony_ci#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x)) 10562306a36Sopenharmony_ci#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x)) 10662306a36Sopenharmony_ci#define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x)) 10762306a36Sopenharmony_ci#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2)) 10862306a36Sopenharmony_ci#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \ 10962306a36Sopenharmony_ci ((x) / 2)) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define ALARM2(x) ((x) << 8) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define ADT7470_VENDOR 0x41 11462306a36Sopenharmony_ci#define ADT7470_DEVICE 0x70 11562306a36Sopenharmony_ci/* datasheet only mentions a revision 2 */ 11662306a36Sopenharmony_ci#define ADT7470_REVISION 0x02 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* "all temps" according to hwmon sysfs interface spec */ 11962306a36Sopenharmony_ci#define ADT7470_PWM_ALL_TEMPS 0x3FF 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* How often do we reread sensors values? (In jiffies) */ 12262306a36Sopenharmony_ci#define SENSOR_REFRESH_INTERVAL (5 * HZ) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* How often do we reread sensor limit values? (In jiffies) */ 12562306a36Sopenharmony_ci#define LIMIT_REFRESH_INTERVAL (60 * HZ) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Wait at least 200ms per sensor for 10 sensors */ 12862306a36Sopenharmony_ci#define TEMP_COLLECTION_TIME 2000 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* auto update thing won't fire more than every 2s */ 13162306a36Sopenharmony_ci#define AUTO_UPDATE_INTERVAL 2000 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* datasheet says to divide this number by the fan reading to get fan rpm */ 13462306a36Sopenharmony_ci#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) 13562306a36Sopenharmony_ci#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM 13662306a36Sopenharmony_ci#define FAN_PERIOD_INVALID 65535 13762306a36Sopenharmony_ci#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* Config registers 1 and 2 include fields for selecting the PWM frequency */ 14062306a36Sopenharmony_ci#define ADT7470_CFG_LF 0x40 14162306a36Sopenharmony_ci#define ADT7470_FREQ_MASK 0x70 14262306a36Sopenharmony_ci#define ADT7470_FREQ_SHIFT 4 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct adt7470_data { 14562306a36Sopenharmony_ci struct regmap *regmap; 14662306a36Sopenharmony_ci struct mutex lock; 14762306a36Sopenharmony_ci char sensors_valid; 14862306a36Sopenharmony_ci char limits_valid; 14962306a36Sopenharmony_ci unsigned long sensors_last_updated; /* In jiffies */ 15062306a36Sopenharmony_ci unsigned long limits_last_updated; /* In jiffies */ 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci int num_temp_sensors; /* -1 = probe */ 15362306a36Sopenharmony_ci int temperatures_probed; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci s8 temp[ADT7470_TEMP_COUNT]; 15662306a36Sopenharmony_ci s8 temp_min[ADT7470_TEMP_COUNT]; 15762306a36Sopenharmony_ci s8 temp_max[ADT7470_TEMP_COUNT]; 15862306a36Sopenharmony_ci u16 fan[ADT7470_FAN_COUNT]; 15962306a36Sopenharmony_ci u16 fan_min[ADT7470_FAN_COUNT]; 16062306a36Sopenharmony_ci u16 fan_max[ADT7470_FAN_COUNT]; 16162306a36Sopenharmony_ci u16 alarm; 16262306a36Sopenharmony_ci u16 alarms_mask; 16362306a36Sopenharmony_ci u8 force_pwm_max; 16462306a36Sopenharmony_ci u8 pwm[ADT7470_PWM_COUNT]; 16562306a36Sopenharmony_ci u8 pwm_max[ADT7470_PWM_COUNT]; 16662306a36Sopenharmony_ci u8 pwm_automatic[ADT7470_PWM_COUNT]; 16762306a36Sopenharmony_ci u8 pwm_min[ADT7470_PWM_COUNT]; 16862306a36Sopenharmony_ci s8 pwm_tmin[ADT7470_PWM_COUNT]; 16962306a36Sopenharmony_ci u8 pwm_auto_temp[ADT7470_PWM_COUNT]; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci struct task_struct *auto_update; 17262306a36Sopenharmony_ci unsigned int auto_update_interval; 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * 16-bit registers on the ADT7470 are low-byte first. The data sheet says 17762306a36Sopenharmony_ci * that the low byte must be read before the high byte. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic inline int adt7470_read_word_data(struct adt7470_data *data, unsigned int reg, 18062306a36Sopenharmony_ci unsigned int *val) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci u8 regval[2]; 18362306a36Sopenharmony_ci int err; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci err = regmap_bulk_read(data->regmap, reg, ®val, 2); 18662306a36Sopenharmony_ci if (err < 0) 18762306a36Sopenharmony_ci return err; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci *val = regval[0] | (regval[1] << 8); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic inline int adt7470_write_word_data(struct adt7470_data *data, unsigned int reg, 19562306a36Sopenharmony_ci unsigned int val) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci u8 regval[2]; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci regval[0] = val & 0xFF; 20062306a36Sopenharmony_ci regval[1] = val >> 8; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return regmap_bulk_write(data->regmap, reg, ®val, 2); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* Probe for temperature sensors. Assumes lock is held */ 20662306a36Sopenharmony_cistatic int adt7470_read_temperatures(struct adt7470_data *data) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned long res; 20962306a36Sopenharmony_ci unsigned int pwm_cfg[2]; 21062306a36Sopenharmony_ci int err; 21162306a36Sopenharmony_ci int i; 21262306a36Sopenharmony_ci u8 pwm[ADT7470_FAN_COUNT]; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* save pwm[1-4] config register */ 21562306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(0), &pwm_cfg[0]); 21662306a36Sopenharmony_ci if (err < 0) 21762306a36Sopenharmony_ci return err; 21862306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(2), &pwm_cfg[1]); 21962306a36Sopenharmony_ci if (err < 0) 22062306a36Sopenharmony_ci return err; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* set manual pwm to whatever it is set to now */ 22362306a36Sopenharmony_ci err = regmap_bulk_read(data->regmap, ADT7470_REG_PWM(0), &pwm[0], 22462306a36Sopenharmony_ci ADT7470_PWM_COUNT); 22562306a36Sopenharmony_ci if (err < 0) 22662306a36Sopenharmony_ci return err; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* put pwm in manual mode */ 22962306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(0), 23062306a36Sopenharmony_ci ADT7470_PWM_AUTO_MASK, 0); 23162306a36Sopenharmony_ci if (err < 0) 23262306a36Sopenharmony_ci return err; 23362306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(2), 23462306a36Sopenharmony_ci ADT7470_PWM_AUTO_MASK, 0); 23562306a36Sopenharmony_ci if (err < 0) 23662306a36Sopenharmony_ci return err; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* write pwm control to whatever it was */ 23962306a36Sopenharmony_ci err = regmap_bulk_write(data->regmap, ADT7470_REG_PWM(0), &pwm[0], 24062306a36Sopenharmony_ci ADT7470_PWM_COUNT); 24162306a36Sopenharmony_ci if (err < 0) 24262306a36Sopenharmony_ci return err; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* start reading temperature sensors */ 24562306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_CFG, 24662306a36Sopenharmony_ci ADT7470_T05_STB_MASK, ADT7470_T05_STB_MASK); 24762306a36Sopenharmony_ci if (err < 0) 24862306a36Sopenharmony_ci return err; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Delay is 200ms * number of temp sensors. */ 25162306a36Sopenharmony_ci res = msleep_interruptible((data->num_temp_sensors >= 0 ? 25262306a36Sopenharmony_ci data->num_temp_sensors * 200 : 25362306a36Sopenharmony_ci TEMP_COLLECTION_TIME)); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* done reading temperature sensors */ 25662306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_CFG, 25762306a36Sopenharmony_ci ADT7470_T05_STB_MASK, 0); 25862306a36Sopenharmony_ci if (err < 0) 25962306a36Sopenharmony_ci return err; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* restore pwm[1-4] config registers */ 26262306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]); 26362306a36Sopenharmony_ci if (err < 0) 26462306a36Sopenharmony_ci return err; 26562306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]); 26662306a36Sopenharmony_ci if (err < 0) 26762306a36Sopenharmony_ci return err; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (res) 27062306a36Sopenharmony_ci return -EAGAIN; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Only count fans if we have to */ 27362306a36Sopenharmony_ci if (data->num_temp_sensors >= 0) 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci err = regmap_bulk_read(data->regmap, ADT7470_TEMP_REG(0), &data->temp[0], 27762306a36Sopenharmony_ci ADT7470_TEMP_COUNT); 27862306a36Sopenharmony_ci if (err < 0) 27962306a36Sopenharmony_ci return err; 28062306a36Sopenharmony_ci for (i = 0; i < ADT7470_TEMP_COUNT; i++) { 28162306a36Sopenharmony_ci if (data->temp[i]) 28262306a36Sopenharmony_ci data->num_temp_sensors = i + 1; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci data->temperatures_probed = 1; 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int adt7470_update_thread(void *p) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct i2c_client *client = p; 29162306a36Sopenharmony_ci struct adt7470_data *data = i2c_get_clientdata(client); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci while (!kthread_should_stop()) { 29462306a36Sopenharmony_ci mutex_lock(&data->lock); 29562306a36Sopenharmony_ci adt7470_read_temperatures(data); 29662306a36Sopenharmony_ci mutex_unlock(&data->lock); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (kthread_should_stop()) 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(data->auto_update_interval)); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int adt7470_update_sensors(struct adt7470_data *data) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci unsigned int val; 31062306a36Sopenharmony_ci int err; 31162306a36Sopenharmony_ci int i; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (!data->temperatures_probed) 31462306a36Sopenharmony_ci err = adt7470_read_temperatures(data); 31562306a36Sopenharmony_ci else 31662306a36Sopenharmony_ci err = regmap_bulk_read(data->regmap, ADT7470_TEMP_REG(0), &data->temp[0], 31762306a36Sopenharmony_ci ADT7470_TEMP_COUNT); 31862306a36Sopenharmony_ci if (err < 0) 31962306a36Sopenharmony_ci return err; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci for (i = 0; i < ADT7470_FAN_COUNT; i++) { 32262306a36Sopenharmony_ci err = adt7470_read_word_data(data, ADT7470_REG_FAN(i), &val); 32362306a36Sopenharmony_ci if (err < 0) 32462306a36Sopenharmony_ci return err; 32562306a36Sopenharmony_ci data->fan[i] = val; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci err = regmap_bulk_read(data->regmap, ADT7470_REG_PWM(0), &data->pwm[0], ADT7470_PWM_COUNT); 32962306a36Sopenharmony_ci if (err < 0) 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0; i < ADT7470_PWM_COUNT; i++) { 33362306a36Sopenharmony_ci unsigned int mask; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (i % 2) 33662306a36Sopenharmony_ci mask = ADT7470_PWM2_AUTO_MASK; 33762306a36Sopenharmony_ci else 33862306a36Sopenharmony_ci mask = ADT7470_PWM1_AUTO_MASK; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(i), &val); 34162306a36Sopenharmony_ci if (err < 0) 34262306a36Sopenharmony_ci return err; 34362306a36Sopenharmony_ci data->pwm_automatic[i] = !!(val & mask); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_AUTO_TEMP(i), &val); 34662306a36Sopenharmony_ci if (err < 0) 34762306a36Sopenharmony_ci return err; 34862306a36Sopenharmony_ci if (!(i % 2)) 34962306a36Sopenharmony_ci data->pwm_auto_temp[i] = val >> 4; 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci data->pwm_auto_temp[i] = val & 0xF; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_CFG, &val); 35562306a36Sopenharmony_ci if (err < 0) 35662306a36Sopenharmony_ci return err; 35762306a36Sopenharmony_ci data->force_pwm_max = !!(val & ADT7470_FSPD_MASK); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_ALARM1, &val); 36062306a36Sopenharmony_ci if (err < 0) 36162306a36Sopenharmony_ci return err; 36262306a36Sopenharmony_ci data->alarm = val; 36362306a36Sopenharmony_ci if (data->alarm & ADT7470_OOL_ALARM) { 36462306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_ALARM2, &val); 36562306a36Sopenharmony_ci if (err < 0) 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci data->alarm |= ALARM2(val); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci err = adt7470_read_word_data(data, ADT7470_REG_ALARM1_MASK, &val); 37162306a36Sopenharmony_ci if (err < 0) 37262306a36Sopenharmony_ci return err; 37362306a36Sopenharmony_ci data->alarms_mask = val; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int adt7470_update_limits(struct adt7470_data *data) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci unsigned int val; 38162306a36Sopenharmony_ci int err; 38262306a36Sopenharmony_ci int i; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci for (i = 0; i < ADT7470_TEMP_COUNT; i++) { 38562306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_TEMP_MIN_REG(i), &val); 38662306a36Sopenharmony_ci if (err < 0) 38762306a36Sopenharmony_ci return err; 38862306a36Sopenharmony_ci data->temp_min[i] = (s8)val; 38962306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_TEMP_MAX_REG(i), &val); 39062306a36Sopenharmony_ci if (err < 0) 39162306a36Sopenharmony_ci return err; 39262306a36Sopenharmony_ci data->temp_max[i] = (s8)val; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci for (i = 0; i < ADT7470_FAN_COUNT; i++) { 39662306a36Sopenharmony_ci err = adt7470_read_word_data(data, ADT7470_REG_FAN_MIN(i), &val); 39762306a36Sopenharmony_ci if (err < 0) 39862306a36Sopenharmony_ci return err; 39962306a36Sopenharmony_ci data->fan_min[i] = val; 40062306a36Sopenharmony_ci err = adt7470_read_word_data(data, ADT7470_REG_FAN_MAX(i), &val); 40162306a36Sopenharmony_ci if (err < 0) 40262306a36Sopenharmony_ci return err; 40362306a36Sopenharmony_ci data->fan_max[i] = val; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci for (i = 0; i < ADT7470_PWM_COUNT; i++) { 40762306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_MAX(i), &val); 40862306a36Sopenharmony_ci if (err < 0) 40962306a36Sopenharmony_ci return err; 41062306a36Sopenharmony_ci data->pwm_max[i] = val; 41162306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_MIN(i), &val); 41262306a36Sopenharmony_ci if (err < 0) 41362306a36Sopenharmony_ci return err; 41462306a36Sopenharmony_ci data->pwm_min[i] = val; 41562306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_PWM_TMIN(i), &val); 41662306a36Sopenharmony_ci if (err < 0) 41762306a36Sopenharmony_ci return err; 41862306a36Sopenharmony_ci data->pwm_tmin[i] = (s8)val; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic struct adt7470_data *adt7470_update_device(struct device *dev) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 42762306a36Sopenharmony_ci unsigned long local_jiffies = jiffies; 42862306a36Sopenharmony_ci int need_sensors = 1; 42962306a36Sopenharmony_ci int need_limits = 1; 43062306a36Sopenharmony_ci int err; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * Figure out if we need to update the shadow registers. 43462306a36Sopenharmony_ci * Lockless means that we may occasionally report out of 43562306a36Sopenharmony_ci * date data. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci if (time_before(local_jiffies, data->sensors_last_updated + 43862306a36Sopenharmony_ci SENSOR_REFRESH_INTERVAL) && 43962306a36Sopenharmony_ci data->sensors_valid) 44062306a36Sopenharmony_ci need_sensors = 0; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (time_before(local_jiffies, data->limits_last_updated + 44362306a36Sopenharmony_ci LIMIT_REFRESH_INTERVAL) && 44462306a36Sopenharmony_ci data->limits_valid) 44562306a36Sopenharmony_ci need_limits = 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!need_sensors && !need_limits) 44862306a36Sopenharmony_ci return data; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci mutex_lock(&data->lock); 45162306a36Sopenharmony_ci if (need_sensors) { 45262306a36Sopenharmony_ci err = adt7470_update_sensors(data); 45362306a36Sopenharmony_ci if (err < 0) 45462306a36Sopenharmony_ci goto out; 45562306a36Sopenharmony_ci data->sensors_last_updated = local_jiffies; 45662306a36Sopenharmony_ci data->sensors_valid = 1; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (need_limits) { 46062306a36Sopenharmony_ci err = adt7470_update_limits(data); 46162306a36Sopenharmony_ci if (err < 0) 46262306a36Sopenharmony_ci goto out; 46362306a36Sopenharmony_ci data->limits_last_updated = local_jiffies; 46462306a36Sopenharmony_ci data->limits_valid = 1; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ciout: 46762306a36Sopenharmony_ci mutex_unlock(&data->lock); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return err < 0 ? ERR_PTR(err) : data; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic ssize_t auto_update_interval_show(struct device *dev, 47362306a36Sopenharmony_ci struct device_attribute *devattr, 47462306a36Sopenharmony_ci char *buf) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (IS_ERR(data)) 47962306a36Sopenharmony_ci return PTR_ERR(data); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->auto_update_interval); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic ssize_t auto_update_interval_store(struct device *dev, 48562306a36Sopenharmony_ci struct device_attribute *devattr, 48662306a36Sopenharmony_ci const char *buf, size_t count) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 48962306a36Sopenharmony_ci long temp; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci temp = clamp_val(temp, 0, 60000); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci mutex_lock(&data->lock); 49762306a36Sopenharmony_ci data->auto_update_interval = temp; 49862306a36Sopenharmony_ci mutex_unlock(&data->lock); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return count; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic ssize_t num_temp_sensors_show(struct device *dev, 50462306a36Sopenharmony_ci struct device_attribute *devattr, 50562306a36Sopenharmony_ci char *buf) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (IS_ERR(data)) 51062306a36Sopenharmony_ci return PTR_ERR(data); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->num_temp_sensors); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic ssize_t num_temp_sensors_store(struct device *dev, 51662306a36Sopenharmony_ci struct device_attribute *devattr, 51762306a36Sopenharmony_ci const char *buf, size_t count) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 52062306a36Sopenharmony_ci long temp; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 52362306a36Sopenharmony_ci return -EINVAL; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci temp = clamp_val(temp, -1, 10); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci mutex_lock(&data->lock); 52862306a36Sopenharmony_ci data->num_temp_sensors = temp; 52962306a36Sopenharmony_ci if (temp < 0) 53062306a36Sopenharmony_ci data->temperatures_probed = 0; 53162306a36Sopenharmony_ci mutex_unlock(&data->lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return count; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int adt7470_temp_read(struct device *dev, u32 attr, int channel, long *val) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (IS_ERR(data)) 54162306a36Sopenharmony_ci return PTR_ERR(data); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci switch (attr) { 54462306a36Sopenharmony_ci case hwmon_temp_input: 54562306a36Sopenharmony_ci *val = 1000 * data->temp[channel]; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci case hwmon_temp_min: 54862306a36Sopenharmony_ci *val = 1000 * data->temp_min[channel]; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case hwmon_temp_max: 55162306a36Sopenharmony_ci *val = 1000 * data->temp_max[channel]; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case hwmon_temp_alarm: 55462306a36Sopenharmony_ci *val = !!(data->alarm & channel); 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci default: 55762306a36Sopenharmony_ci return -EOPNOTSUPP; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int adt7470_temp_write(struct device *dev, u32 attr, int channel, long val) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 56662306a36Sopenharmony_ci int err; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci val = clamp_val(val, -128000, 127000); 56962306a36Sopenharmony_ci val = DIV_ROUND_CLOSEST(val, 1000); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci switch (attr) { 57262306a36Sopenharmony_ci case hwmon_temp_min: 57362306a36Sopenharmony_ci mutex_lock(&data->lock); 57462306a36Sopenharmony_ci data->temp_min[channel] = val; 57562306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_TEMP_MIN_REG(channel), val); 57662306a36Sopenharmony_ci mutex_unlock(&data->lock); 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci case hwmon_temp_max: 57962306a36Sopenharmony_ci mutex_lock(&data->lock); 58062306a36Sopenharmony_ci data->temp_max[channel] = val; 58162306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_TEMP_MAX_REG(channel), val); 58262306a36Sopenharmony_ci mutex_unlock(&data->lock); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci default: 58562306a36Sopenharmony_ci return -EOPNOTSUPP; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return err; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic ssize_t alarm_mask_show(struct device *dev, 59262306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (IS_ERR(data)) 59762306a36Sopenharmony_ci return PTR_ERR(data); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return sprintf(buf, "%x\n", data->alarms_mask); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic ssize_t alarm_mask_store(struct device *dev, 60362306a36Sopenharmony_ci struct device_attribute *devattr, 60462306a36Sopenharmony_ci const char *buf, size_t count) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 60762306a36Sopenharmony_ci long mask; 60862306a36Sopenharmony_ci int err; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (kstrtoul(buf, 0, &mask)) 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (mask & ~0xffff) 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci mutex_lock(&data->lock); 61762306a36Sopenharmony_ci data->alarms_mask = mask; 61862306a36Sopenharmony_ci err = adt7470_write_word_data(data, ADT7470_REG_ALARM1_MASK, mask); 61962306a36Sopenharmony_ci mutex_unlock(&data->lock); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci return err < 0 ? err : count; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic int adt7470_fan_read(struct device *dev, u32 attr, int channel, long *val) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (IS_ERR(data)) 62962306a36Sopenharmony_ci return PTR_ERR(data); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci switch (attr) { 63262306a36Sopenharmony_ci case hwmon_fan_input: 63362306a36Sopenharmony_ci if (FAN_DATA_VALID(data->fan[channel])) 63462306a36Sopenharmony_ci *val = FAN_PERIOD_TO_RPM(data->fan[channel]); 63562306a36Sopenharmony_ci else 63662306a36Sopenharmony_ci *val = 0; 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci case hwmon_fan_min: 63962306a36Sopenharmony_ci if (FAN_DATA_VALID(data->fan_min[channel])) 64062306a36Sopenharmony_ci *val = FAN_PERIOD_TO_RPM(data->fan_min[channel]); 64162306a36Sopenharmony_ci else 64262306a36Sopenharmony_ci *val = 0; 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci case hwmon_fan_max: 64562306a36Sopenharmony_ci if (FAN_DATA_VALID(data->fan_max[channel])) 64662306a36Sopenharmony_ci *val = FAN_PERIOD_TO_RPM(data->fan_max[channel]); 64762306a36Sopenharmony_ci else 64862306a36Sopenharmony_ci *val = 0; 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci case hwmon_fan_alarm: 65162306a36Sopenharmony_ci *val = !!(data->alarm & (1 << (12 + channel))); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci default: 65462306a36Sopenharmony_ci return -EOPNOTSUPP; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int adt7470_fan_write(struct device *dev, u32 attr, int channel, long val) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 66362306a36Sopenharmony_ci int err; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (val <= 0) 66662306a36Sopenharmony_ci return -EINVAL; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci val = FAN_RPM_TO_PERIOD(val); 66962306a36Sopenharmony_ci val = clamp_val(val, 1, 65534); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci switch (attr) { 67262306a36Sopenharmony_ci case hwmon_fan_min: 67362306a36Sopenharmony_ci mutex_lock(&data->lock); 67462306a36Sopenharmony_ci data->fan_min[channel] = val; 67562306a36Sopenharmony_ci err = adt7470_write_word_data(data, ADT7470_REG_FAN_MIN(channel), val); 67662306a36Sopenharmony_ci mutex_unlock(&data->lock); 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci case hwmon_fan_max: 67962306a36Sopenharmony_ci mutex_lock(&data->lock); 68062306a36Sopenharmony_ci data->fan_max[channel] = val; 68162306a36Sopenharmony_ci err = adt7470_write_word_data(data, ADT7470_REG_FAN_MAX(channel), val); 68262306a36Sopenharmony_ci mutex_unlock(&data->lock); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci default: 68562306a36Sopenharmony_ci return -EOPNOTSUPP; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci return err; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic ssize_t force_pwm_max_show(struct device *dev, 69262306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (IS_ERR(data)) 69762306a36Sopenharmony_ci return PTR_ERR(data); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->force_pwm_max); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic ssize_t force_pwm_max_store(struct device *dev, 70362306a36Sopenharmony_ci struct device_attribute *devattr, 70462306a36Sopenharmony_ci const char *buf, size_t count) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 70762306a36Sopenharmony_ci long temp; 70862306a36Sopenharmony_ci int err; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci mutex_lock(&data->lock); 71462306a36Sopenharmony_ci data->force_pwm_max = temp; 71562306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_CFG, 71662306a36Sopenharmony_ci ADT7470_FSPD_MASK, 71762306a36Sopenharmony_ci temp ? ADT7470_FSPD_MASK : 0); 71862306a36Sopenharmony_ci mutex_unlock(&data->lock); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return err < 0 ? err : count; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci/* These are the valid PWM frequencies to the nearest Hz */ 72462306a36Sopenharmony_cistatic const int adt7470_freq_map[] = { 72562306a36Sopenharmony_ci 11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500 72662306a36Sopenharmony_ci}; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int pwm1_freq_get(struct device *dev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 73162306a36Sopenharmony_ci unsigned int cfg_reg_1, cfg_reg_2; 73262306a36Sopenharmony_ci int index; 73362306a36Sopenharmony_ci int err; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci mutex_lock(&data->lock); 73662306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_CFG, &cfg_reg_1); 73762306a36Sopenharmony_ci if (err < 0) 73862306a36Sopenharmony_ci goto out; 73962306a36Sopenharmony_ci err = regmap_read(data->regmap, ADT7470_REG_CFG_2, &cfg_reg_2); 74062306a36Sopenharmony_ci if (err < 0) 74162306a36Sopenharmony_ci goto out; 74262306a36Sopenharmony_ci mutex_unlock(&data->lock); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci index = (cfg_reg_2 & ADT7470_FREQ_MASK) >> ADT7470_FREQ_SHIFT; 74562306a36Sopenharmony_ci if (!(cfg_reg_1 & ADT7470_CFG_LF)) 74662306a36Sopenharmony_ci index += 8; 74762306a36Sopenharmony_ci if (index >= ARRAY_SIZE(adt7470_freq_map)) 74862306a36Sopenharmony_ci index = ARRAY_SIZE(adt7470_freq_map) - 1; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return adt7470_freq_map[index]; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ciout: 75362306a36Sopenharmony_ci mutex_unlock(&data->lock); 75462306a36Sopenharmony_ci return err; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int adt7470_pwm_read(struct device *dev, u32 attr, int channel, long *val) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (IS_ERR(data)) 76262306a36Sopenharmony_ci return PTR_ERR(data); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci switch (attr) { 76562306a36Sopenharmony_ci case hwmon_pwm_input: 76662306a36Sopenharmony_ci *val = data->pwm[channel]; 76762306a36Sopenharmony_ci break; 76862306a36Sopenharmony_ci case hwmon_pwm_enable: 76962306a36Sopenharmony_ci *val = 1 + data->pwm_automatic[channel]; 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci case hwmon_pwm_freq: 77262306a36Sopenharmony_ci *val = pwm1_freq_get(dev); 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci default: 77562306a36Sopenharmony_ci return -EOPNOTSUPP; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic int pwm1_freq_set(struct device *dev, long freq) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 78462306a36Sopenharmony_ci unsigned int low_freq = ADT7470_CFG_LF; 78562306a36Sopenharmony_ci int index; 78662306a36Sopenharmony_ci int err; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* Round the user value given to the closest available frequency */ 78962306a36Sopenharmony_ci index = find_closest(freq, adt7470_freq_map, 79062306a36Sopenharmony_ci ARRAY_SIZE(adt7470_freq_map)); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (index >= 8) { 79362306a36Sopenharmony_ci index -= 8; 79462306a36Sopenharmony_ci low_freq = 0; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci mutex_lock(&data->lock); 79862306a36Sopenharmony_ci /* Configuration Register 1 */ 79962306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_CFG, 80062306a36Sopenharmony_ci ADT7470_CFG_LF, low_freq); 80162306a36Sopenharmony_ci if (err < 0) 80262306a36Sopenharmony_ci goto out; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* Configuration Register 2 */ 80562306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_CFG_2, 80662306a36Sopenharmony_ci ADT7470_FREQ_MASK, 80762306a36Sopenharmony_ci index << ADT7470_FREQ_SHIFT); 80862306a36Sopenharmony_ciout: 80962306a36Sopenharmony_ci mutex_unlock(&data->lock); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return err; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 81762306a36Sopenharmony_ci unsigned int pwm_auto_reg_mask; 81862306a36Sopenharmony_ci int err; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci switch (attr) { 82162306a36Sopenharmony_ci case hwmon_pwm_input: 82262306a36Sopenharmony_ci val = clamp_val(val, 0, 255); 82362306a36Sopenharmony_ci mutex_lock(&data->lock); 82462306a36Sopenharmony_ci data->pwm[channel] = val; 82562306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_REG_PWM(channel), 82662306a36Sopenharmony_ci data->pwm[channel]); 82762306a36Sopenharmony_ci mutex_unlock(&data->lock); 82862306a36Sopenharmony_ci break; 82962306a36Sopenharmony_ci case hwmon_pwm_enable: 83062306a36Sopenharmony_ci if (channel % 2) 83162306a36Sopenharmony_ci pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK; 83262306a36Sopenharmony_ci else 83362306a36Sopenharmony_ci pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (val != 2 && val != 1) 83662306a36Sopenharmony_ci return -EINVAL; 83762306a36Sopenharmony_ci val--; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci mutex_lock(&data->lock); 84062306a36Sopenharmony_ci data->pwm_automatic[channel] = val; 84162306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(channel), 84262306a36Sopenharmony_ci pwm_auto_reg_mask, 84362306a36Sopenharmony_ci val ? pwm_auto_reg_mask : 0); 84462306a36Sopenharmony_ci mutex_unlock(&data->lock); 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci case hwmon_pwm_freq: 84762306a36Sopenharmony_ci err = pwm1_freq_set(dev, val); 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci default: 85062306a36Sopenharmony_ci return -EOPNOTSUPP; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return err; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic ssize_t pwm_max_show(struct device *dev, 85762306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 86062306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (IS_ERR(data)) 86362306a36Sopenharmony_ci return PTR_ERR(data); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->pwm_max[attr->index]); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic ssize_t pwm_max_store(struct device *dev, 86962306a36Sopenharmony_ci struct device_attribute *devattr, 87062306a36Sopenharmony_ci const char *buf, size_t count) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 87362306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 87462306a36Sopenharmony_ci long temp; 87562306a36Sopenharmony_ci int err; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 87862306a36Sopenharmony_ci return -EINVAL; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci temp = clamp_val(temp, 0, 255); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci mutex_lock(&data->lock); 88362306a36Sopenharmony_ci data->pwm_max[attr->index] = temp; 88462306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_REG_PWM_MAX(attr->index), 88562306a36Sopenharmony_ci temp); 88662306a36Sopenharmony_ci mutex_unlock(&data->lock); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return err < 0 ? err : count; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic ssize_t pwm_min_show(struct device *dev, 89262306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 89562306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (IS_ERR(data)) 89862306a36Sopenharmony_ci return PTR_ERR(data); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->pwm_min[attr->index]); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic ssize_t pwm_min_store(struct device *dev, 90462306a36Sopenharmony_ci struct device_attribute *devattr, 90562306a36Sopenharmony_ci const char *buf, size_t count) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 90862306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 90962306a36Sopenharmony_ci long temp; 91062306a36Sopenharmony_ci int err; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 91362306a36Sopenharmony_ci return -EINVAL; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci temp = clamp_val(temp, 0, 255); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci mutex_lock(&data->lock); 91862306a36Sopenharmony_ci data->pwm_min[attr->index] = temp; 91962306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_REG_PWM_MIN(attr->index), 92062306a36Sopenharmony_ci temp); 92162306a36Sopenharmony_ci mutex_unlock(&data->lock); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return err < 0 ? err : count; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic ssize_t pwm_tmax_show(struct device *dev, 92762306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 93062306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (IS_ERR(data)) 93362306a36Sopenharmony_ci return PTR_ERR(data); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* the datasheet says that tmax = tmin + 20C */ 93662306a36Sopenharmony_ci return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index])); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic ssize_t pwm_tmin_show(struct device *dev, 94062306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 94362306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (IS_ERR(data)) 94662306a36Sopenharmony_ci return PTR_ERR(data); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]); 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic ssize_t pwm_tmin_store(struct device *dev, 95262306a36Sopenharmony_ci struct device_attribute *devattr, 95362306a36Sopenharmony_ci const char *buf, size_t count) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 95662306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 95762306a36Sopenharmony_ci long temp; 95862306a36Sopenharmony_ci int err; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 96162306a36Sopenharmony_ci return -EINVAL; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci temp = clamp_val(temp, -128000, 127000); 96462306a36Sopenharmony_ci temp = DIV_ROUND_CLOSEST(temp, 1000); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci mutex_lock(&data->lock); 96762306a36Sopenharmony_ci data->pwm_tmin[attr->index] = temp; 96862306a36Sopenharmony_ci err = regmap_write(data->regmap, ADT7470_REG_PWM_TMIN(attr->index), 96962306a36Sopenharmony_ci temp); 97062306a36Sopenharmony_ci mutex_unlock(&data->lock); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci return err < 0 ? err : count; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic ssize_t pwm_auto_temp_show(struct device *dev, 97662306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 97962306a36Sopenharmony_ci struct adt7470_data *data = adt7470_update_device(dev); 98062306a36Sopenharmony_ci u8 ctrl; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (IS_ERR(data)) 98362306a36Sopenharmony_ci return PTR_ERR(data); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci ctrl = data->pwm_auto_temp[attr->index]; 98662306a36Sopenharmony_ci if (ctrl) 98762306a36Sopenharmony_ci return sprintf(buf, "%d\n", 1 << (ctrl - 1)); 98862306a36Sopenharmony_ci else 98962306a36Sopenharmony_ci return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic int cvt_auto_temp(int input) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci if (input == ADT7470_PWM_ALL_TEMPS) 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci if (input < 1 || !is_power_of_2(input)) 99762306a36Sopenharmony_ci return -EINVAL; 99862306a36Sopenharmony_ci return ilog2(input) + 1; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic ssize_t pwm_auto_temp_store(struct device *dev, 100262306a36Sopenharmony_ci struct device_attribute *devattr, 100362306a36Sopenharmony_ci const char *buf, size_t count) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 100662306a36Sopenharmony_ci struct adt7470_data *data = dev_get_drvdata(dev); 100762306a36Sopenharmony_ci int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index); 100862306a36Sopenharmony_ci unsigned int mask, val; 100962306a36Sopenharmony_ci long temp; 101062306a36Sopenharmony_ci int err; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (kstrtol(buf, 10, &temp)) 101362306a36Sopenharmony_ci return -EINVAL; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci temp = cvt_auto_temp(temp); 101662306a36Sopenharmony_ci if (temp < 0) 101762306a36Sopenharmony_ci return temp; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci mutex_lock(&data->lock); 102062306a36Sopenharmony_ci data->pwm_automatic[attr->index] = temp; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (!(attr->index % 2)) { 102362306a36Sopenharmony_ci mask = 0xF0; 102462306a36Sopenharmony_ci val = (temp << 4) & 0xF0; 102562306a36Sopenharmony_ci } else { 102662306a36Sopenharmony_ci mask = 0x0F; 102762306a36Sopenharmony_ci val = temp & 0x0F; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, pwm_auto_reg, mask, val); 103162306a36Sopenharmony_ci mutex_unlock(&data->lock); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci return err < 0 ? err : count; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(alarm_mask); 103762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(num_temp_sensors); 103862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(auto_update_interval); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(force_pwm_max, force_pwm_max, 0); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_pwm, pwm_min, 0); 104362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_point1_pwm, pwm_min, 1); 104462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3_auto_point1_pwm, pwm_min, 2); 104562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm4_auto_point1_pwm, pwm_min, 3); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_pwm, pwm_max, 0); 104862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_point2_pwm, pwm_max, 1); 104962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3_auto_point2_pwm, pwm_max, 2); 105062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm4_auto_point2_pwm, pwm_max, 3); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, pwm_tmin, 0); 105362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_point1_temp, pwm_tmin, 1); 105462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3_auto_point1_temp, pwm_tmin, 2); 105562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm4_auto_point1_temp, pwm_tmin, 3); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(pwm1_auto_point2_temp, pwm_tmax, 0); 105862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(pwm2_auto_point2_temp, pwm_tmax, 1); 105962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(pwm3_auto_point2_temp, pwm_tmax, 2); 106062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(pwm4_auto_point2_temp, pwm_tmax, 3); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_channels_temp, pwm_auto_temp, 0); 106362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_channels_temp, pwm_auto_temp, 1); 106462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm3_auto_channels_temp, pwm_auto_temp, 2); 106562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm4_auto_channels_temp, pwm_auto_temp, 3); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic struct attribute *adt7470_attrs[] = { 106862306a36Sopenharmony_ci &dev_attr_alarm_mask.attr, 106962306a36Sopenharmony_ci &dev_attr_num_temp_sensors.attr, 107062306a36Sopenharmony_ci &dev_attr_auto_update_interval.attr, 107162306a36Sopenharmony_ci &sensor_dev_attr_force_pwm_max.dev_attr.attr, 107262306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 107362306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, 107462306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, 107562306a36Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr, 107662306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, 107762306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, 107862306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, 107962306a36Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr, 108062306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, 108162306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, 108262306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, 108362306a36Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr, 108462306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, 108562306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, 108662306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, 108762306a36Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr, 108862306a36Sopenharmony_ci &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, 108962306a36Sopenharmony_ci &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, 109062306a36Sopenharmony_ci &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, 109162306a36Sopenharmony_ci &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr, 109262306a36Sopenharmony_ci NULL 109362306a36Sopenharmony_ci}; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciATTRIBUTE_GROUPS(adt7470); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int adt7470_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 109862306a36Sopenharmony_ci int channel, long *val) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci switch (type) { 110162306a36Sopenharmony_ci case hwmon_temp: 110262306a36Sopenharmony_ci return adt7470_temp_read(dev, attr, channel, val); 110362306a36Sopenharmony_ci case hwmon_fan: 110462306a36Sopenharmony_ci return adt7470_fan_read(dev, attr, channel, val); 110562306a36Sopenharmony_ci case hwmon_pwm: 110662306a36Sopenharmony_ci return adt7470_pwm_read(dev, attr, channel, val); 110762306a36Sopenharmony_ci default: 110862306a36Sopenharmony_ci return -EOPNOTSUPP; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic int adt7470_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, 111362306a36Sopenharmony_ci int channel, long val) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci switch (type) { 111662306a36Sopenharmony_ci case hwmon_temp: 111762306a36Sopenharmony_ci return adt7470_temp_write(dev, attr, channel, val); 111862306a36Sopenharmony_ci case hwmon_fan: 111962306a36Sopenharmony_ci return adt7470_fan_write(dev, attr, channel, val); 112062306a36Sopenharmony_ci case hwmon_pwm: 112162306a36Sopenharmony_ci return adt7470_pwm_write(dev, attr, channel, val); 112262306a36Sopenharmony_ci default: 112362306a36Sopenharmony_ci return -EOPNOTSUPP; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic umode_t adt7470_is_visible(const void *_data, enum hwmon_sensor_types type, 112862306a36Sopenharmony_ci u32 attr, int channel) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci umode_t mode = 0; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci switch (type) { 113362306a36Sopenharmony_ci case hwmon_temp: 113462306a36Sopenharmony_ci switch (attr) { 113562306a36Sopenharmony_ci case hwmon_temp: 113662306a36Sopenharmony_ci case hwmon_temp_alarm: 113762306a36Sopenharmony_ci mode = 0444; 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci case hwmon_temp_min: 114062306a36Sopenharmony_ci case hwmon_temp_max: 114162306a36Sopenharmony_ci mode = 0644; 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci default: 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci break; 114762306a36Sopenharmony_ci case hwmon_fan: 114862306a36Sopenharmony_ci switch (attr) { 114962306a36Sopenharmony_ci case hwmon_fan_input: 115062306a36Sopenharmony_ci case hwmon_fan_alarm: 115162306a36Sopenharmony_ci mode = 0444; 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci case hwmon_fan_min: 115462306a36Sopenharmony_ci case hwmon_fan_max: 115562306a36Sopenharmony_ci mode = 0644; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci default: 115862306a36Sopenharmony_ci break; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci break; 116162306a36Sopenharmony_ci case hwmon_pwm: 116262306a36Sopenharmony_ci switch (attr) { 116362306a36Sopenharmony_ci case hwmon_pwm_input: 116462306a36Sopenharmony_ci case hwmon_pwm_enable: 116562306a36Sopenharmony_ci mode = 0644; 116662306a36Sopenharmony_ci break; 116762306a36Sopenharmony_ci case hwmon_pwm_freq: 116862306a36Sopenharmony_ci if (channel == 0) 116962306a36Sopenharmony_ci mode = 0644; 117062306a36Sopenharmony_ci else 117162306a36Sopenharmony_ci mode = 0; 117262306a36Sopenharmony_ci break; 117362306a36Sopenharmony_ci default: 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci break; 117762306a36Sopenharmony_ci default: 117862306a36Sopenharmony_ci break; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci return mode; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic const struct hwmon_ops adt7470_hwmon_ops = { 118562306a36Sopenharmony_ci .is_visible = adt7470_is_visible, 118662306a36Sopenharmony_ci .read = adt7470_read, 118762306a36Sopenharmony_ci .write = adt7470_write, 118862306a36Sopenharmony_ci}; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic const struct hwmon_channel_info * const adt7470_info[] = { 119162306a36Sopenharmony_ci HWMON_CHANNEL_INFO(temp, 119262306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119362306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119462306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119562306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119662306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119762306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119862306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 119962306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 120062306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, 120162306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM), 120262306a36Sopenharmony_ci HWMON_CHANNEL_INFO(fan, 120362306a36Sopenharmony_ci HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX | HWMON_F_DIV | HWMON_F_ALARM, 120462306a36Sopenharmony_ci HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX | HWMON_F_DIV | HWMON_F_ALARM, 120562306a36Sopenharmony_ci HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX | HWMON_F_DIV | HWMON_F_ALARM, 120662306a36Sopenharmony_ci HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX | HWMON_F_DIV | HWMON_F_ALARM), 120762306a36Sopenharmony_ci HWMON_CHANNEL_INFO(pwm, 120862306a36Sopenharmony_ci HWMON_PWM_INPUT | HWMON_PWM_ENABLE | HWMON_PWM_FREQ, 120962306a36Sopenharmony_ci HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 121062306a36Sopenharmony_ci HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 121162306a36Sopenharmony_ci HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 121262306a36Sopenharmony_ci NULL 121362306a36Sopenharmony_ci}; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic const struct hwmon_chip_info adt7470_chip_info = { 121662306a36Sopenharmony_ci .ops = &adt7470_hwmon_ops, 121762306a36Sopenharmony_ci .info = adt7470_info, 121862306a36Sopenharmony_ci}; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 122162306a36Sopenharmony_cistatic int adt7470_detect(struct i2c_client *client, 122262306a36Sopenharmony_ci struct i2c_board_info *info) 122362306a36Sopenharmony_ci{ 122462306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 122562306a36Sopenharmony_ci int vendor, device, revision; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 122862306a36Sopenharmony_ci return -ENODEV; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR); 123162306a36Sopenharmony_ci if (vendor != ADT7470_VENDOR) 123262306a36Sopenharmony_ci return -ENODEV; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE); 123562306a36Sopenharmony_ci if (device != ADT7470_DEVICE) 123662306a36Sopenharmony_ci return -ENODEV; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci revision = i2c_smbus_read_byte_data(client, ADT7470_REG_REVISION); 123962306a36Sopenharmony_ci if (revision != ADT7470_REVISION) 124062306a36Sopenharmony_ci return -ENODEV; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci strscpy(info->type, "adt7470", I2C_NAME_SIZE); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci return 0; 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cistatic const struct regmap_config adt7470_regmap_config = { 124862306a36Sopenharmony_ci .reg_bits = 8, 124962306a36Sopenharmony_ci .val_bits = 8, 125062306a36Sopenharmony_ci .use_single_read = true, 125162306a36Sopenharmony_ci .use_single_write = true, 125262306a36Sopenharmony_ci}; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic int adt7470_probe(struct i2c_client *client) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci struct device *dev = &client->dev; 125762306a36Sopenharmony_ci struct adt7470_data *data; 125862306a36Sopenharmony_ci struct device *hwmon_dev; 125962306a36Sopenharmony_ci int err; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct adt7470_data), GFP_KERNEL); 126262306a36Sopenharmony_ci if (!data) 126362306a36Sopenharmony_ci return -ENOMEM; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci data->num_temp_sensors = -1; 126662306a36Sopenharmony_ci data->auto_update_interval = AUTO_UPDATE_INTERVAL; 126762306a36Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &adt7470_regmap_config); 126862306a36Sopenharmony_ci if (IS_ERR(data->regmap)) 126962306a36Sopenharmony_ci return PTR_ERR(data->regmap); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci i2c_set_clientdata(client, data); 127262306a36Sopenharmony_ci mutex_init(&data->lock); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci dev_info(&client->dev, "%s chip found\n", client->name); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Initialize the ADT7470 chip */ 127762306a36Sopenharmony_ci err = regmap_update_bits(data->regmap, ADT7470_REG_CFG, 127862306a36Sopenharmony_ci ADT7470_STRT_MASK | ADT7470_TEST_MASK, 127962306a36Sopenharmony_ci ADT7470_STRT_MASK | ADT7470_TEST_MASK); 128062306a36Sopenharmony_ci if (err < 0) 128162306a36Sopenharmony_ci return err; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* Register sysfs hooks */ 128462306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, 128562306a36Sopenharmony_ci &adt7470_chip_info, 128662306a36Sopenharmony_ci adt7470_groups); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (IS_ERR(hwmon_dev)) 128962306a36Sopenharmony_ci return PTR_ERR(hwmon_dev); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci data->auto_update = kthread_run(adt7470_update_thread, client, "%s", 129262306a36Sopenharmony_ci dev_name(hwmon_dev)); 129362306a36Sopenharmony_ci if (IS_ERR(data->auto_update)) 129462306a36Sopenharmony_ci return PTR_ERR(data->auto_update); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic void adt7470_remove(struct i2c_client *client) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct adt7470_data *data = i2c_get_clientdata(client); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci kthread_stop(data->auto_update); 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic const struct i2c_device_id adt7470_id[] = { 130762306a36Sopenharmony_ci { "adt7470", 0 }, 130862306a36Sopenharmony_ci { } 130962306a36Sopenharmony_ci}; 131062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adt7470_id); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic struct i2c_driver adt7470_driver = { 131362306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 131462306a36Sopenharmony_ci .driver = { 131562306a36Sopenharmony_ci .name = "adt7470", 131662306a36Sopenharmony_ci }, 131762306a36Sopenharmony_ci .probe = adt7470_probe, 131862306a36Sopenharmony_ci .remove = adt7470_remove, 131962306a36Sopenharmony_ci .id_table = adt7470_id, 132062306a36Sopenharmony_ci .detect = adt7470_detect, 132162306a36Sopenharmony_ci .address_list = normal_i2c, 132262306a36Sopenharmony_ci}; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cimodule_i2c_driver(adt7470_driver); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ciMODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>"); 132762306a36Sopenharmony_ciMODULE_DESCRIPTION("ADT7470 driver"); 132862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1329