162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * adm1031.c - Part of lm_sensors, Linux kernel modules for hardware 462306a36Sopenharmony_ci * monitoring 562306a36Sopenharmony_ci * Based on lm75.c and lm85.c 662306a36Sopenharmony_ci * Supports adm1030 / adm1031 762306a36Sopenharmony_ci * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org> 862306a36Sopenharmony_ci * Reworked by Jean Delvare <jdelvare@suse.de> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/jiffies.h> 1562306a36Sopenharmony_ci#include <linux/i2c.h> 1662306a36Sopenharmony_ci#include <linux/hwmon.h> 1762306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1862306a36Sopenharmony_ci#include <linux/err.h> 1962306a36Sopenharmony_ci#include <linux/mutex.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Following macros takes channel parameter starting from 0 to 2 */ 2262306a36Sopenharmony_ci#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) 2362306a36Sopenharmony_ci#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) 2462306a36Sopenharmony_ci#define ADM1031_REG_PWM (0x22) 2562306a36Sopenharmony_ci#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) 2662306a36Sopenharmony_ci#define ADM1031_REG_FAN_FILTER (0x23) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define ADM1031_REG_TEMP_OFFSET(nr) (0x0d + (nr)) 2962306a36Sopenharmony_ci#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr)) 3062306a36Sopenharmony_ci#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr)) 3162306a36Sopenharmony_ci#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr)) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define ADM1031_REG_TEMP(nr) (0x0a + (nr)) 3462306a36Sopenharmony_ci#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ADM1031_REG_STATUS(nr) (0x2 + (nr)) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define ADM1031_REG_CONF1 0x00 3962306a36Sopenharmony_ci#define ADM1031_REG_CONF2 0x01 4062306a36Sopenharmony_ci#define ADM1031_REG_EXT_TEMP 0x06 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ 4362306a36Sopenharmony_ci#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ 4462306a36Sopenharmony_ci#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define ADM1031_CONF2_PWM1_ENABLE 0x01 4762306a36Sopenharmony_ci#define ADM1031_CONF2_PWM2_ENABLE 0x02 4862306a36Sopenharmony_ci#define ADM1031_CONF2_TACH1_ENABLE 0x04 4962306a36Sopenharmony_ci#define ADM1031_CONF2_TACH2_ENABLE 0x08 5062306a36Sopenharmony_ci#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define ADM1031_UPDATE_RATE_MASK 0x1c 5362306a36Sopenharmony_ci#define ADM1031_UPDATE_RATE_SHIFT 2 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* Addresses to scan */ 5662306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cienum chips { adm1030, adm1031 }; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_citypedef u8 auto_chan_table_t[8][2]; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Each client has this additional data */ 6362306a36Sopenharmony_cistruct adm1031_data { 6462306a36Sopenharmony_ci struct i2c_client *client; 6562306a36Sopenharmony_ci const struct attribute_group *groups[3]; 6662306a36Sopenharmony_ci struct mutex update_lock; 6762306a36Sopenharmony_ci int chip_type; 6862306a36Sopenharmony_ci bool valid; /* true if following fields are valid */ 6962306a36Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 7062306a36Sopenharmony_ci unsigned int update_interval; /* In milliseconds */ 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * The chan_select_table contains the possible configurations for 7362306a36Sopenharmony_ci * auto fan control. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci const auto_chan_table_t *chan_select_table; 7662306a36Sopenharmony_ci u16 alarm; 7762306a36Sopenharmony_ci u8 conf1; 7862306a36Sopenharmony_ci u8 conf2; 7962306a36Sopenharmony_ci u8 fan[2]; 8062306a36Sopenharmony_ci u8 fan_div[2]; 8162306a36Sopenharmony_ci u8 fan_min[2]; 8262306a36Sopenharmony_ci u8 pwm[2]; 8362306a36Sopenharmony_ci u8 old_pwm[2]; 8462306a36Sopenharmony_ci s8 temp[3]; 8562306a36Sopenharmony_ci u8 ext_temp[3]; 8662306a36Sopenharmony_ci u8 auto_temp[3]; 8762306a36Sopenharmony_ci u8 auto_temp_min[3]; 8862306a36Sopenharmony_ci u8 auto_temp_off[3]; 8962306a36Sopenharmony_ci u8 auto_temp_max[3]; 9062306a36Sopenharmony_ci s8 temp_offset[3]; 9162306a36Sopenharmony_ci s8 temp_min[3]; 9262306a36Sopenharmony_ci s8 temp_max[3]; 9362306a36Sopenharmony_ci s8 temp_crit[3]; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci return i2c_smbus_read_byte_data(client, reg); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic inline int 10262306a36Sopenharmony_ciadm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return i2c_smbus_write_byte_data(client, reg, value); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic struct adm1031_data *adm1031_update_device(struct device *dev) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 11062306a36Sopenharmony_ci struct i2c_client *client = data->client; 11162306a36Sopenharmony_ci unsigned long next_update; 11262306a36Sopenharmony_ci int chan; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci next_update = data->last_updated 11762306a36Sopenharmony_ci + msecs_to_jiffies(data->update_interval); 11862306a36Sopenharmony_ci if (time_after(jiffies, next_update) || !data->valid) { 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci dev_dbg(&client->dev, "Starting adm1031 update\n"); 12162306a36Sopenharmony_ci for (chan = 0; 12262306a36Sopenharmony_ci chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) { 12362306a36Sopenharmony_ci u8 oldh, newh; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci oldh = 12662306a36Sopenharmony_ci adm1031_read_value(client, ADM1031_REG_TEMP(chan)); 12762306a36Sopenharmony_ci data->ext_temp[chan] = 12862306a36Sopenharmony_ci adm1031_read_value(client, ADM1031_REG_EXT_TEMP); 12962306a36Sopenharmony_ci newh = 13062306a36Sopenharmony_ci adm1031_read_value(client, ADM1031_REG_TEMP(chan)); 13162306a36Sopenharmony_ci if (newh != oldh) { 13262306a36Sopenharmony_ci data->ext_temp[chan] = 13362306a36Sopenharmony_ci adm1031_read_value(client, 13462306a36Sopenharmony_ci ADM1031_REG_EXT_TEMP); 13562306a36Sopenharmony_ci#ifdef DEBUG 13662306a36Sopenharmony_ci oldh = 13762306a36Sopenharmony_ci adm1031_read_value(client, 13862306a36Sopenharmony_ci ADM1031_REG_TEMP(chan)); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* oldh is actually newer */ 14162306a36Sopenharmony_ci if (newh != oldh) 14262306a36Sopenharmony_ci dev_warn(&client->dev, 14362306a36Sopenharmony_ci "Remote temperature may be wrong.\n"); 14462306a36Sopenharmony_ci#endif 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci data->temp[chan] = newh; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci data->temp_offset[chan] = 14962306a36Sopenharmony_ci adm1031_read_value(client, 15062306a36Sopenharmony_ci ADM1031_REG_TEMP_OFFSET(chan)); 15162306a36Sopenharmony_ci data->temp_min[chan] = 15262306a36Sopenharmony_ci adm1031_read_value(client, 15362306a36Sopenharmony_ci ADM1031_REG_TEMP_MIN(chan)); 15462306a36Sopenharmony_ci data->temp_max[chan] = 15562306a36Sopenharmony_ci adm1031_read_value(client, 15662306a36Sopenharmony_ci ADM1031_REG_TEMP_MAX(chan)); 15762306a36Sopenharmony_ci data->temp_crit[chan] = 15862306a36Sopenharmony_ci adm1031_read_value(client, 15962306a36Sopenharmony_ci ADM1031_REG_TEMP_CRIT(chan)); 16062306a36Sopenharmony_ci data->auto_temp[chan] = 16162306a36Sopenharmony_ci adm1031_read_value(client, 16262306a36Sopenharmony_ci ADM1031_REG_AUTO_TEMP(chan)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); 16762306a36Sopenharmony_ci data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) 17062306a36Sopenharmony_ci | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8); 17162306a36Sopenharmony_ci if (data->chip_type == adm1030) 17262306a36Sopenharmony_ci data->alarm &= 0xc0ff; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2); 17562306a36Sopenharmony_ci chan++) { 17662306a36Sopenharmony_ci data->fan_div[chan] = 17762306a36Sopenharmony_ci adm1031_read_value(client, 17862306a36Sopenharmony_ci ADM1031_REG_FAN_DIV(chan)); 17962306a36Sopenharmony_ci data->fan_min[chan] = 18062306a36Sopenharmony_ci adm1031_read_value(client, 18162306a36Sopenharmony_ci ADM1031_REG_FAN_MIN(chan)); 18262306a36Sopenharmony_ci data->fan[chan] = 18362306a36Sopenharmony_ci adm1031_read_value(client, 18462306a36Sopenharmony_ci ADM1031_REG_FAN_SPEED(chan)); 18562306a36Sopenharmony_ci data->pwm[chan] = 18662306a36Sopenharmony_ci (adm1031_read_value(client, 18762306a36Sopenharmony_ci ADM1031_REG_PWM) >> (4 * chan)) & 0x0f; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci data->last_updated = jiffies; 19062306a36Sopenharmony_ci data->valid = true; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return data; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \ 19962306a36Sopenharmony_ci ((val + 500) / 1000))) 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define TEMP_FROM_REG(val) ((val) * 1000) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125) 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#define TEMP_OFFSET_TO_REG(val) (TEMP_TO_REG(val) & 0x8f) 20662306a36Sopenharmony_ci#define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \ 20762306a36Sopenharmony_ci (val) | 0x70 : (val)) 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci#define FAN_FROM_REG(reg, div) ((reg) ? \ 21062306a36Sopenharmony_ci (11250 * 60) / ((reg) * (div)) : 0) 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int FAN_TO_REG(int reg, int div) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int tmp; 21562306a36Sopenharmony_ci tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div); 21662306a36Sopenharmony_ci return tmp > 255 ? 255 : tmp; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci#define PWM_TO_REG(val) (clamp_val((val), 0, 255) >> 4) 22262306a36Sopenharmony_ci#define PWM_FROM_REG(val) ((val) << 4) 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) 22562306a36Sopenharmony_ci#define FAN_CHAN_TO_REG(val, reg) \ 22662306a36Sopenharmony_ci (((reg) & 0x1F) | (((val) << 5) & 0xe0)) 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define AUTO_TEMP_MIN_TO_REG(val, reg) \ 22962306a36Sopenharmony_ci ((((val) / 500) & 0xf8) | ((reg) & 0x7)) 23062306a36Sopenharmony_ci#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7))) 23162306a36Sopenharmony_ci#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define AUTO_TEMP_OFF_FROM_REG(reg) \ 23662306a36Sopenharmony_ci (AUTO_TEMP_MIN_FROM_REG(reg) - 5000) 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#define AUTO_TEMP_MAX_FROM_REG(reg) \ 23962306a36Sopenharmony_ci (AUTO_TEMP_RANGE_FROM_REG(reg) + \ 24062306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG(reg)) 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci int ret; 24562306a36Sopenharmony_ci int range = ((val - AUTO_TEMP_MIN_FROM_REG(reg)) * 10) / (16 - pwm); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ret = ((reg & 0xf8) | 24862306a36Sopenharmony_ci (range < 10000 ? 0 : 24962306a36Sopenharmony_ci range < 20000 ? 1 : 25062306a36Sopenharmony_ci range < 40000 ? 2 : range < 80000 ? 3 : 4)); 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* FAN auto control */ 25562306a36Sopenharmony_ci#define GET_FAN_AUTO_BITFIELD(data, idx) \ 25662306a36Sopenharmony_ci (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2] 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * The tables below contains the possible values for the auto fan 26062306a36Sopenharmony_ci * control bitfields. the index in the table is the register value. 26162306a36Sopenharmony_ci * MSb is the auto fan control enable bit, so the four first entries 26262306a36Sopenharmony_ci * in the table disables auto fan control when both bitfields are zero. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistatic const auto_chan_table_t auto_channel_select_table_adm1031 = { 26562306a36Sopenharmony_ci { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 26662306a36Sopenharmony_ci { 2 /* 0b010 */ , 4 /* 0b100 */ }, 26762306a36Sopenharmony_ci { 2 /* 0b010 */ , 2 /* 0b010 */ }, 26862306a36Sopenharmony_ci { 4 /* 0b100 */ , 4 /* 0b100 */ }, 26962306a36Sopenharmony_ci { 7 /* 0b111 */ , 7 /* 0b111 */ }, 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic const auto_chan_table_t auto_channel_select_table_adm1030 = { 27362306a36Sopenharmony_ci { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 27462306a36Sopenharmony_ci { 2 /* 0b10 */ , 0 }, 27562306a36Sopenharmony_ci { 0xff /* invalid */ , 0 }, 27662306a36Sopenharmony_ci { 0xff /* invalid */ , 0 }, 27762306a36Sopenharmony_ci { 3 /* 0b11 */ , 0 }, 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* 28162306a36Sopenharmony_ci * That function checks if a bitfield is valid and returns the other bitfield 28262306a36Sopenharmony_ci * nearest match if no exact match where found. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_cistatic int 28562306a36Sopenharmony_ciget_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int i; 28862306a36Sopenharmony_ci int first_match = -1, exact_match = -1; 28962306a36Sopenharmony_ci u8 other_reg_val = 29062306a36Sopenharmony_ci (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (val == 0) 29362306a36Sopenharmony_ci return 0; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 29662306a36Sopenharmony_ci if ((val == (*data->chan_select_table)[i][chan]) && 29762306a36Sopenharmony_ci ((*data->chan_select_table)[i][chan ? 0 : 1] == 29862306a36Sopenharmony_ci other_reg_val)) { 29962306a36Sopenharmony_ci /* We found an exact match */ 30062306a36Sopenharmony_ci exact_match = i; 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci } else if (val == (*data->chan_select_table)[i][chan] && 30362306a36Sopenharmony_ci first_match == -1) { 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * Save the first match in case of an exact match has 30662306a36Sopenharmony_ci * not been found 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci first_match = i; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (exact_match >= 0) 31362306a36Sopenharmony_ci return exact_match; 31462306a36Sopenharmony_ci else if (first_match >= 0) 31562306a36Sopenharmony_ci return first_match; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic ssize_t fan_auto_channel_show(struct device *dev, 32162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 32462306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 32562306a36Sopenharmony_ci return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic ssize_t 32962306a36Sopenharmony_cifan_auto_channel_store(struct device *dev, struct device_attribute *attr, 33062306a36Sopenharmony_ci const char *buf, size_t count) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 33362306a36Sopenharmony_ci struct i2c_client *client = data->client; 33462306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 33562306a36Sopenharmony_ci long val; 33662306a36Sopenharmony_ci u8 reg; 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci u8 old_fan_mode; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 34162306a36Sopenharmony_ci if (ret) 34262306a36Sopenharmony_ci return ret; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci old_fan_mode = data->conf1; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ret = get_fan_auto_nearest(data, nr, val, data->conf1); 34962306a36Sopenharmony_ci if (ret < 0) { 35062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci reg = ret; 35462306a36Sopenharmony_ci data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); 35562306a36Sopenharmony_ci if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ 35662306a36Sopenharmony_ci (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { 35762306a36Sopenharmony_ci if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * Switch to Auto Fan Mode 36062306a36Sopenharmony_ci * Save PWM registers 36162306a36Sopenharmony_ci * Set PWM registers to 33% Both 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci data->old_pwm[0] = data->pwm[0]; 36462306a36Sopenharmony_ci data->old_pwm[1] = data->pwm[1]; 36562306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_PWM, 0x55); 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci /* Switch to Manual Mode */ 36862306a36Sopenharmony_ci data->pwm[0] = data->old_pwm[0]; 36962306a36Sopenharmony_ci data->pwm[1] = data->old_pwm[1]; 37062306a36Sopenharmony_ci /* Restore PWM registers */ 37162306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_PWM, 37262306a36Sopenharmony_ci data->pwm[0] | (data->pwm[1] << 4)); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); 37662306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); 37762306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 37862306a36Sopenharmony_ci return count; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan1_channel, fan_auto_channel, 0); 38262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan2_channel, fan_auto_channel, 1); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci/* Auto Temps */ 38562306a36Sopenharmony_cistatic ssize_t auto_temp_off_show(struct device *dev, 38662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 38962306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 39062306a36Sopenharmony_ci return sprintf(buf, "%d\n", 39162306a36Sopenharmony_ci AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_cistatic ssize_t auto_temp_min_show(struct device *dev, 39462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 39762306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 39862306a36Sopenharmony_ci return sprintf(buf, "%d\n", 39962306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_cistatic ssize_t 40262306a36Sopenharmony_ciauto_temp_min_store(struct device *dev, struct device_attribute *attr, 40362306a36Sopenharmony_ci const char *buf, size_t count) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 40662306a36Sopenharmony_ci struct i2c_client *client = data->client; 40762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 40862306a36Sopenharmony_ci long val; 40962306a36Sopenharmony_ci int ret; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 41262306a36Sopenharmony_ci if (ret) 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci val = clamp_val(val, 0, 127000); 41662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 41762306a36Sopenharmony_ci data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); 41862306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), 41962306a36Sopenharmony_ci data->auto_temp[nr]); 42062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 42162306a36Sopenharmony_ci return count; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_cistatic ssize_t auto_temp_max_show(struct device *dev, 42462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 42762306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 42862306a36Sopenharmony_ci return sprintf(buf, "%d\n", 42962306a36Sopenharmony_ci AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_cistatic ssize_t 43262306a36Sopenharmony_ciauto_temp_max_store(struct device *dev, struct device_attribute *attr, 43362306a36Sopenharmony_ci const char *buf, size_t count) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 43662306a36Sopenharmony_ci struct i2c_client *client = data->client; 43762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 43862306a36Sopenharmony_ci long val; 43962306a36Sopenharmony_ci int ret; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 44262306a36Sopenharmony_ci if (ret) 44362306a36Sopenharmony_ci return ret; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci val = clamp_val(val, 0, 127000); 44662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 44762306a36Sopenharmony_ci data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], 44862306a36Sopenharmony_ci data->pwm[nr]); 44962306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), 45062306a36Sopenharmony_ci data->temp_max[nr]); 45162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 45262306a36Sopenharmony_ci return count; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(auto_temp1_off, auto_temp_off, 0); 45662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp1_min, auto_temp_min, 0); 45762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp1_max, auto_temp_max, 0); 45862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(auto_temp2_off, auto_temp_off, 1); 45962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp2_min, auto_temp_min, 1); 46062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp2_max, auto_temp_max, 1); 46162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(auto_temp3_off, auto_temp_off, 2); 46262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp3_min, auto_temp_min, 2); 46362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp3_max, auto_temp_max, 2); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci/* pwm */ 46662306a36Sopenharmony_cistatic ssize_t pwm_show(struct device *dev, struct device_attribute *attr, 46762306a36Sopenharmony_ci char *buf) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 47062306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 47162306a36Sopenharmony_ci return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_cistatic ssize_t pwm_store(struct device *dev, struct device_attribute *attr, 47462306a36Sopenharmony_ci const char *buf, size_t count) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 47762306a36Sopenharmony_ci struct i2c_client *client = data->client; 47862306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 47962306a36Sopenharmony_ci long val; 48062306a36Sopenharmony_ci int ret, reg; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 48362306a36Sopenharmony_ci if (ret) 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 48762306a36Sopenharmony_ci if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && 48862306a36Sopenharmony_ci (((val>>4) & 0xf) != 5)) { 48962306a36Sopenharmony_ci /* In automatic mode, the only PWM accepted is 33% */ 49062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 49162306a36Sopenharmony_ci return -EINVAL; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci data->pwm[nr] = PWM_TO_REG(val); 49462306a36Sopenharmony_ci reg = adm1031_read_value(client, ADM1031_REG_PWM); 49562306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_PWM, 49662306a36Sopenharmony_ci nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf) 49762306a36Sopenharmony_ci : (data->pwm[nr] & 0xf) | (reg & 0xf0)); 49862306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 49962306a36Sopenharmony_ci return count; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 50362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); 50462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan1_min_pwm, pwm, 0); 50562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan2_min_pwm, pwm, 1); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci/* Fans */ 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/* 51062306a36Sopenharmony_ci * That function checks the cases where the fan reading is not 51162306a36Sopenharmony_ci * relevant. It is used to provide 0 as fan reading when the fan is 51262306a36Sopenharmony_ci * not supposed to run 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistatic int trust_fan_readings(struct adm1031_data *data, int chan) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci int res = 0; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { 51962306a36Sopenharmony_ci switch (data->conf1 & 0x60) { 52062306a36Sopenharmony_ci case 0x00: 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * remote temp1 controls fan1, 52362306a36Sopenharmony_ci * remote temp2 controls fan2 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci res = data->temp[chan+1] >= 52662306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci case 0x20: /* remote temp1 controls both fans */ 52962306a36Sopenharmony_ci res = 53062306a36Sopenharmony_ci data->temp[1] >= 53162306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci case 0x40: /* remote temp2 controls both fans */ 53462306a36Sopenharmony_ci res = 53562306a36Sopenharmony_ci data->temp[2] >= 53662306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case 0x60: /* max controls both fans */ 53962306a36Sopenharmony_ci res = 54062306a36Sopenharmony_ci data->temp[0] >= 54162306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) 54262306a36Sopenharmony_ci || data->temp[1] >= 54362306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) 54462306a36Sopenharmony_ci || (data->chip_type == adm1031 54562306a36Sopenharmony_ci && data->temp[2] >= 54662306a36Sopenharmony_ci AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci } else { 55062306a36Sopenharmony_ci res = data->pwm[chan] > 0; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci return res; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic ssize_t fan_show(struct device *dev, struct device_attribute *attr, 55662306a36Sopenharmony_ci char *buf) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 55962306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 56062306a36Sopenharmony_ci int value; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr], 56362306a36Sopenharmony_ci FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; 56462306a36Sopenharmony_ci return sprintf(buf, "%d\n", value); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic ssize_t fan_div_show(struct device *dev, struct device_attribute *attr, 56862306a36Sopenharmony_ci char *buf) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 57162306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 57262306a36Sopenharmony_ci return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_cistatic ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, 57562306a36Sopenharmony_ci char *buf) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 57862306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 57962306a36Sopenharmony_ci return sprintf(buf, "%d\n", 58062306a36Sopenharmony_ci FAN_FROM_REG(data->fan_min[nr], 58162306a36Sopenharmony_ci FAN_DIV_FROM_REG(data->fan_div[nr]))); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_cistatic ssize_t fan_min_store(struct device *dev, 58462306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 58562306a36Sopenharmony_ci size_t count) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 58862306a36Sopenharmony_ci struct i2c_client *client = data->client; 58962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 59062306a36Sopenharmony_ci long val; 59162306a36Sopenharmony_ci int ret; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 59462306a36Sopenharmony_ci if (ret) 59562306a36Sopenharmony_ci return ret; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 59862306a36Sopenharmony_ci if (val) { 59962306a36Sopenharmony_ci data->fan_min[nr] = 60062306a36Sopenharmony_ci FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci data->fan_min[nr] = 0xff; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); 60562306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 60662306a36Sopenharmony_ci return count; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_cistatic ssize_t fan_div_store(struct device *dev, 60962306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 61062306a36Sopenharmony_ci size_t count) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 61362306a36Sopenharmony_ci struct i2c_client *client = data->client; 61462306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 61562306a36Sopenharmony_ci long val; 61662306a36Sopenharmony_ci u8 tmp; 61762306a36Sopenharmony_ci int old_div; 61862306a36Sopenharmony_ci int new_min; 61962306a36Sopenharmony_ci int ret; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 62262306a36Sopenharmony_ci if (ret) 62362306a36Sopenharmony_ci return ret; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci tmp = val == 8 ? 0xc0 : 62662306a36Sopenharmony_ci val == 4 ? 0x80 : 62762306a36Sopenharmony_ci val == 2 ? 0x40 : 62862306a36Sopenharmony_ci val == 1 ? 0x00 : 62962306a36Sopenharmony_ci 0xff; 63062306a36Sopenharmony_ci if (tmp == 0xff) 63162306a36Sopenharmony_ci return -EINVAL; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 63462306a36Sopenharmony_ci /* Get fresh readings */ 63562306a36Sopenharmony_ci data->fan_div[nr] = adm1031_read_value(client, 63662306a36Sopenharmony_ci ADM1031_REG_FAN_DIV(nr)); 63762306a36Sopenharmony_ci data->fan_min[nr] = adm1031_read_value(client, 63862306a36Sopenharmony_ci ADM1031_REG_FAN_MIN(nr)); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Write the new clock divider and fan min */ 64162306a36Sopenharmony_ci old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); 64262306a36Sopenharmony_ci data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]); 64362306a36Sopenharmony_ci new_min = data->fan_min[nr] * old_div / val; 64462306a36Sopenharmony_ci data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), 64762306a36Sopenharmony_ci data->fan_div[nr]); 64862306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), 64962306a36Sopenharmony_ci data->fan_min[nr]); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Invalidate the cache: fan speed is no longer valid */ 65262306a36Sopenharmony_ci data->valid = false; 65362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 65462306a36Sopenharmony_ci return count; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0); 65862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); 65962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0); 66062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1); 66162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); 66262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci/* Temps */ 66562306a36Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *attr, 66662306a36Sopenharmony_ci char *buf) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 66962306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 67062306a36Sopenharmony_ci int ext; 67162306a36Sopenharmony_ci ext = nr == 0 ? 67262306a36Sopenharmony_ci ((data->ext_temp[nr] >> 6) & 0x3) * 2 : 67362306a36Sopenharmony_ci (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); 67462306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_cistatic ssize_t temp_offset_show(struct device *dev, 67762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 68062306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 68162306a36Sopenharmony_ci return sprintf(buf, "%d\n", 68262306a36Sopenharmony_ci TEMP_OFFSET_FROM_REG(data->temp_offset[nr])); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_cistatic ssize_t temp_min_show(struct device *dev, 68562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 68862306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 68962306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_cistatic ssize_t temp_max_show(struct device *dev, 69262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 69562306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 69662306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_cistatic ssize_t temp_crit_show(struct device *dev, 69962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 70262306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 70362306a36Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_cistatic ssize_t temp_offset_store(struct device *dev, 70662306a36Sopenharmony_ci struct device_attribute *attr, 70762306a36Sopenharmony_ci const char *buf, size_t count) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 71062306a36Sopenharmony_ci struct i2c_client *client = data->client; 71162306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 71262306a36Sopenharmony_ci long val; 71362306a36Sopenharmony_ci int ret; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 71662306a36Sopenharmony_ci if (ret) 71762306a36Sopenharmony_ci return ret; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci val = clamp_val(val, -15000, 15000); 72062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 72162306a36Sopenharmony_ci data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val); 72262306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr), 72362306a36Sopenharmony_ci data->temp_offset[nr]); 72462306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 72562306a36Sopenharmony_ci return count; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_cistatic ssize_t temp_min_store(struct device *dev, 72862306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 72962306a36Sopenharmony_ci size_t count) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 73262306a36Sopenharmony_ci struct i2c_client *client = data->client; 73362306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 73462306a36Sopenharmony_ci long val; 73562306a36Sopenharmony_ci int ret; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 73862306a36Sopenharmony_ci if (ret) 73962306a36Sopenharmony_ci return ret; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci val = clamp_val(val, -55000, 127000); 74262306a36Sopenharmony_ci mutex_lock(&data->update_lock); 74362306a36Sopenharmony_ci data->temp_min[nr] = TEMP_TO_REG(val); 74462306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), 74562306a36Sopenharmony_ci data->temp_min[nr]); 74662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 74762306a36Sopenharmony_ci return count; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_cistatic ssize_t temp_max_store(struct device *dev, 75062306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 75162306a36Sopenharmony_ci size_t count) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 75462306a36Sopenharmony_ci struct i2c_client *client = data->client; 75562306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 75662306a36Sopenharmony_ci long val; 75762306a36Sopenharmony_ci int ret; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 76062306a36Sopenharmony_ci if (ret) 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci val = clamp_val(val, -55000, 127000); 76462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 76562306a36Sopenharmony_ci data->temp_max[nr] = TEMP_TO_REG(val); 76662306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), 76762306a36Sopenharmony_ci data->temp_max[nr]); 76862306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 76962306a36Sopenharmony_ci return count; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_cistatic ssize_t temp_crit_store(struct device *dev, 77262306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 77362306a36Sopenharmony_ci size_t count) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 77662306a36Sopenharmony_ci struct i2c_client *client = data->client; 77762306a36Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 77862306a36Sopenharmony_ci long val; 77962306a36Sopenharmony_ci int ret; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 78262306a36Sopenharmony_ci if (ret) 78362306a36Sopenharmony_ci return ret; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci val = clamp_val(val, -55000, 127000); 78662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 78762306a36Sopenharmony_ci data->temp_crit[nr] = TEMP_TO_REG(val); 78862306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), 78962306a36Sopenharmony_ci data->temp_crit[nr]); 79062306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 79162306a36Sopenharmony_ci return count; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 79562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_offset, temp_offset, 0); 79662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0); 79762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); 79862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit, temp_crit, 0); 79962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); 80062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_offset, temp_offset, 1); 80162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1); 80262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); 80362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_crit, temp_crit, 1); 80462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); 80562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_offset, temp_offset, 2); 80662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2); 80762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); 80862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_crit, temp_crit, 2); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci/* Alarms */ 81162306a36Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr, 81262306a36Sopenharmony_ci char *buf) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 81562306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->alarm); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *attr, 82162306a36Sopenharmony_ci char *buf) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 82462306a36Sopenharmony_ci struct adm1031_data *data = adm1031_update_device(dev); 82562306a36Sopenharmony_ci return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 0); 82962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, 1); 83062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, alarm, 2); 83162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, alarm, 3); 83262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_crit_alarm, alarm, 4); 83362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 5); 83462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 6); 83562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 7); 83662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 8); 83762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_fault, alarm, 9); 83862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, alarm, 10); 83962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_min_alarm, alarm, 11); 84062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_crit_alarm, alarm, 12); 84162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 13); 84262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 14); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci/* Update Interval */ 84562306a36Sopenharmony_cistatic const unsigned int update_intervals[] = { 84662306a36Sopenharmony_ci 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 84762306a36Sopenharmony_ci}; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic ssize_t update_interval_show(struct device *dev, 85062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci return sprintf(buf, "%u\n", data->update_interval); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic ssize_t update_interval_store(struct device *dev, 85862306a36Sopenharmony_ci struct device_attribute *attr, 85962306a36Sopenharmony_ci const char *buf, size_t count) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct adm1031_data *data = dev_get_drvdata(dev); 86262306a36Sopenharmony_ci struct i2c_client *client = data->client; 86362306a36Sopenharmony_ci unsigned long val; 86462306a36Sopenharmony_ci int i, err; 86562306a36Sopenharmony_ci u8 reg; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 86862306a36Sopenharmony_ci if (err) 86962306a36Sopenharmony_ci return err; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* 87262306a36Sopenharmony_ci * Find the nearest update interval from the table. 87362306a36Sopenharmony_ci * Use it to determine the matching update rate. 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) { 87662306a36Sopenharmony_ci if (val >= update_intervals[i]) 87762306a36Sopenharmony_ci break; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci /* if not found, we point to the last entry (lowest update interval) */ 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* set the new update rate while preserving other settings */ 88262306a36Sopenharmony_ci reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER); 88362306a36Sopenharmony_ci reg &= ~ADM1031_UPDATE_RATE_MASK; 88462306a36Sopenharmony_ci reg |= i << ADM1031_UPDATE_RATE_SHIFT; 88562306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 88862306a36Sopenharmony_ci data->update_interval = update_intervals[i]; 88962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return count; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(update_interval); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic struct attribute *adm1031_attributes[] = { 89762306a36Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 89862306a36Sopenharmony_ci &sensor_dev_attr_fan1_div.dev_attr.attr, 89962306a36Sopenharmony_ci &sensor_dev_attr_fan1_min.dev_attr.attr, 90062306a36Sopenharmony_ci &sensor_dev_attr_fan1_alarm.dev_attr.attr, 90162306a36Sopenharmony_ci &sensor_dev_attr_fan1_fault.dev_attr.attr, 90262306a36Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 90362306a36Sopenharmony_ci &sensor_dev_attr_auto_fan1_channel.dev_attr.attr, 90462306a36Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 90562306a36Sopenharmony_ci &sensor_dev_attr_temp1_offset.dev_attr.attr, 90662306a36Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 90762306a36Sopenharmony_ci &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 90862306a36Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 90962306a36Sopenharmony_ci &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 91062306a36Sopenharmony_ci &sensor_dev_attr_temp1_crit.dev_attr.attr, 91162306a36Sopenharmony_ci &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, 91262306a36Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, 91362306a36Sopenharmony_ci &sensor_dev_attr_temp2_offset.dev_attr.attr, 91462306a36Sopenharmony_ci &sensor_dev_attr_temp2_min.dev_attr.attr, 91562306a36Sopenharmony_ci &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, 91662306a36Sopenharmony_ci &sensor_dev_attr_temp2_max.dev_attr.attr, 91762306a36Sopenharmony_ci &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, 91862306a36Sopenharmony_ci &sensor_dev_attr_temp2_crit.dev_attr.attr, 91962306a36Sopenharmony_ci &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, 92062306a36Sopenharmony_ci &sensor_dev_attr_temp2_fault.dev_attr.attr, 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci &sensor_dev_attr_auto_temp1_off.dev_attr.attr, 92362306a36Sopenharmony_ci &sensor_dev_attr_auto_temp1_min.dev_attr.attr, 92462306a36Sopenharmony_ci &sensor_dev_attr_auto_temp1_max.dev_attr.attr, 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci &sensor_dev_attr_auto_temp2_off.dev_attr.attr, 92762306a36Sopenharmony_ci &sensor_dev_attr_auto_temp2_min.dev_attr.attr, 92862306a36Sopenharmony_ci &sensor_dev_attr_auto_temp2_max.dev_attr.attr, 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr, 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci &dev_attr_update_interval.attr, 93362306a36Sopenharmony_ci &dev_attr_alarms.attr, 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci NULL 93662306a36Sopenharmony_ci}; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic const struct attribute_group adm1031_group = { 93962306a36Sopenharmony_ci .attrs = adm1031_attributes, 94062306a36Sopenharmony_ci}; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic struct attribute *adm1031_attributes_opt[] = { 94362306a36Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 94462306a36Sopenharmony_ci &sensor_dev_attr_fan2_div.dev_attr.attr, 94562306a36Sopenharmony_ci &sensor_dev_attr_fan2_min.dev_attr.attr, 94662306a36Sopenharmony_ci &sensor_dev_attr_fan2_alarm.dev_attr.attr, 94762306a36Sopenharmony_ci &sensor_dev_attr_fan2_fault.dev_attr.attr, 94862306a36Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 94962306a36Sopenharmony_ci &sensor_dev_attr_auto_fan2_channel.dev_attr.attr, 95062306a36Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr.attr, 95162306a36Sopenharmony_ci &sensor_dev_attr_temp3_offset.dev_attr.attr, 95262306a36Sopenharmony_ci &sensor_dev_attr_temp3_min.dev_attr.attr, 95362306a36Sopenharmony_ci &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, 95462306a36Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr.attr, 95562306a36Sopenharmony_ci &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, 95662306a36Sopenharmony_ci &sensor_dev_attr_temp3_crit.dev_attr.attr, 95762306a36Sopenharmony_ci &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, 95862306a36Sopenharmony_ci &sensor_dev_attr_temp3_fault.dev_attr.attr, 95962306a36Sopenharmony_ci &sensor_dev_attr_auto_temp3_off.dev_attr.attr, 96062306a36Sopenharmony_ci &sensor_dev_attr_auto_temp3_min.dev_attr.attr, 96162306a36Sopenharmony_ci &sensor_dev_attr_auto_temp3_max.dev_attr.attr, 96262306a36Sopenharmony_ci &sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr, 96362306a36Sopenharmony_ci NULL 96462306a36Sopenharmony_ci}; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic const struct attribute_group adm1031_group_opt = { 96762306a36Sopenharmony_ci .attrs = adm1031_attributes_opt, 96862306a36Sopenharmony_ci}; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 97162306a36Sopenharmony_cistatic int adm1031_detect(struct i2c_client *client, 97262306a36Sopenharmony_ci struct i2c_board_info *info) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 97562306a36Sopenharmony_ci const char *name; 97662306a36Sopenharmony_ci int id, co; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 97962306a36Sopenharmony_ci return -ENODEV; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci id = i2c_smbus_read_byte_data(client, 0x3d); 98262306a36Sopenharmony_ci co = i2c_smbus_read_byte_data(client, 0x3e); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (!((id == 0x31 || id == 0x30) && co == 0x41)) 98562306a36Sopenharmony_ci return -ENODEV; 98662306a36Sopenharmony_ci name = (id == 0x30) ? "adm1030" : "adm1031"; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci strscpy(info->type, name, I2C_NAME_SIZE); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return 0; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic void adm1031_init_client(struct i2c_client *client) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci unsigned int read_val; 99662306a36Sopenharmony_ci unsigned int mask; 99762306a36Sopenharmony_ci int i; 99862306a36Sopenharmony_ci struct adm1031_data *data = i2c_get_clientdata(client); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); 100162306a36Sopenharmony_ci if (data->chip_type == adm1031) { 100262306a36Sopenharmony_ci mask |= (ADM1031_CONF2_PWM2_ENABLE | 100362306a36Sopenharmony_ci ADM1031_CONF2_TACH2_ENABLE); 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci /* Initialize the ADM1031 chip (enables fan speed reading ) */ 100662306a36Sopenharmony_ci read_val = adm1031_read_value(client, ADM1031_REG_CONF2); 100762306a36Sopenharmony_ci if ((read_val | mask) != read_val) 100862306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci read_val = adm1031_read_value(client, ADM1031_REG_CONF1); 101162306a36Sopenharmony_ci if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { 101262306a36Sopenharmony_ci adm1031_write_value(client, ADM1031_REG_CONF1, 101362306a36Sopenharmony_ci read_val | ADM1031_CONF1_MONITOR_ENABLE); 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Read the chip's update rate */ 101762306a36Sopenharmony_ci mask = ADM1031_UPDATE_RATE_MASK; 101862306a36Sopenharmony_ci read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER); 101962306a36Sopenharmony_ci i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT; 102062306a36Sopenharmony_ci /* Save it as update interval */ 102162306a36Sopenharmony_ci data->update_interval = update_intervals[i]; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic const struct i2c_device_id adm1031_id[]; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic int adm1031_probe(struct i2c_client *client) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct device *dev = &client->dev; 102962306a36Sopenharmony_ci struct device *hwmon_dev; 103062306a36Sopenharmony_ci struct adm1031_data *data; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct adm1031_data), GFP_KERNEL); 103362306a36Sopenharmony_ci if (!data) 103462306a36Sopenharmony_ci return -ENOMEM; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci i2c_set_clientdata(client, data); 103762306a36Sopenharmony_ci data->client = client; 103862306a36Sopenharmony_ci data->chip_type = i2c_match_id(adm1031_id, client)->driver_data; 103962306a36Sopenharmony_ci mutex_init(&data->update_lock); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (data->chip_type == adm1030) 104262306a36Sopenharmony_ci data->chan_select_table = &auto_channel_select_table_adm1030; 104362306a36Sopenharmony_ci else 104462306a36Sopenharmony_ci data->chan_select_table = &auto_channel_select_table_adm1031; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* Initialize the ADM1031 chip */ 104762306a36Sopenharmony_ci adm1031_init_client(client); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* sysfs hooks */ 105062306a36Sopenharmony_ci data->groups[0] = &adm1031_group; 105162306a36Sopenharmony_ci if (data->chip_type == adm1031) 105262306a36Sopenharmony_ci data->groups[1] = &adm1031_group_opt; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 105562306a36Sopenharmony_ci data, data->groups); 105662306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic const struct i2c_device_id adm1031_id[] = { 106062306a36Sopenharmony_ci { "adm1030", adm1030 }, 106162306a36Sopenharmony_ci { "adm1031", adm1031 }, 106262306a36Sopenharmony_ci { } 106362306a36Sopenharmony_ci}; 106462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adm1031_id); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic struct i2c_driver adm1031_driver = { 106762306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 106862306a36Sopenharmony_ci .driver = { 106962306a36Sopenharmony_ci .name = "adm1031", 107062306a36Sopenharmony_ci }, 107162306a36Sopenharmony_ci .probe = adm1031_probe, 107262306a36Sopenharmony_ci .id_table = adm1031_id, 107362306a36Sopenharmony_ci .detect = adm1031_detect, 107462306a36Sopenharmony_ci .address_list = normal_i2c, 107562306a36Sopenharmony_ci}; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cimodule_i2c_driver(adm1031_driver); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ciMODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>"); 108062306a36Sopenharmony_ciMODULE_DESCRIPTION("ADM1031/ADM1030 driver"); 108162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1082