162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201 462306a36Sopenharmony_ci * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/jiffies.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/hwmon.h> 1362306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Addresses to scan 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * The EMC6W201 registers 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define EMC6W201_REG_IN(nr) (0x20 + (nr)) 2862306a36Sopenharmony_ci#define EMC6W201_REG_TEMP(nr) (0x26 + (nr)) 2962306a36Sopenharmony_ci#define EMC6W201_REG_FAN(nr) (0x2C + (nr) * 2) 3062306a36Sopenharmony_ci#define EMC6W201_REG_COMPANY 0x3E 3162306a36Sopenharmony_ci#define EMC6W201_REG_VERSTEP 0x3F 3262306a36Sopenharmony_ci#define EMC6W201_REG_CONFIG 0x40 3362306a36Sopenharmony_ci#define EMC6W201_REG_IN_LOW(nr) (0x4A + (nr) * 2) 3462306a36Sopenharmony_ci#define EMC6W201_REG_IN_HIGH(nr) (0x4B + (nr) * 2) 3562306a36Sopenharmony_ci#define EMC6W201_REG_TEMP_LOW(nr) (0x56 + (nr) * 2) 3662306a36Sopenharmony_ci#define EMC6W201_REG_TEMP_HIGH(nr) (0x57 + (nr) * 2) 3762306a36Sopenharmony_ci#define EMC6W201_REG_FAN_MIN(nr) (0x62 + (nr) * 2) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cienum subfeature { input, min, max }; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Per-device data 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct emc6w201_data { 4662306a36Sopenharmony_ci struct i2c_client *client; 4762306a36Sopenharmony_ci struct mutex update_lock; 4862306a36Sopenharmony_ci bool valid; /* false until following fields are valid */ 4962306a36Sopenharmony_ci unsigned long last_updated; /* in jiffies */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* registers values */ 5262306a36Sopenharmony_ci u8 in[3][6]; 5362306a36Sopenharmony_ci s8 temp[3][6]; 5462306a36Sopenharmony_ci u16 fan[2][5]; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Combine LSB and MSB registers in a single value 5962306a36Sopenharmony_ci * Locking: must be called with data->update_lock held 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistatic u16 emc6w201_read16(struct i2c_client *client, u8 reg) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci int lsb, msb; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci lsb = i2c_smbus_read_byte_data(client, reg); 6662306a36Sopenharmony_ci msb = i2c_smbus_read_byte_data(client, reg + 1); 6762306a36Sopenharmony_ci if (unlikely(lsb < 0 || msb < 0)) { 6862306a36Sopenharmony_ci dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n", 6962306a36Sopenharmony_ci 16, "read", reg); 7062306a36Sopenharmony_ci return 0xFFFF; /* Arbitrary value */ 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return (msb << 8) | lsb; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Write 16-bit value to LSB and MSB registers 7862306a36Sopenharmony_ci * Locking: must be called with data->update_lock held 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int err; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci err = i2c_smbus_write_byte_data(client, reg, val & 0xff); 8562306a36Sopenharmony_ci if (likely(!err)) 8662306a36Sopenharmony_ci err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8); 8762306a36Sopenharmony_ci if (unlikely(err < 0)) 8862306a36Sopenharmony_ci dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n", 8962306a36Sopenharmony_ci 16, "write", reg); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return err; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* Read 8-bit value from register */ 9562306a36Sopenharmony_cistatic u8 emc6w201_read8(struct i2c_client *client, u8 reg) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci int val; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci val = i2c_smbus_read_byte_data(client, reg); 10062306a36Sopenharmony_ci if (unlikely(val < 0)) { 10162306a36Sopenharmony_ci dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n", 10262306a36Sopenharmony_ci 8, "read", reg); 10362306a36Sopenharmony_ci return 0x00; /* Arbitrary value */ 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return val; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* Write 8-bit value to register */ 11062306a36Sopenharmony_cistatic int emc6w201_write8(struct i2c_client *client, u8 reg, u8 val) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci int err; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci err = i2c_smbus_write_byte_data(client, reg, val); 11562306a36Sopenharmony_ci if (unlikely(err < 0)) 11662306a36Sopenharmony_ci dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n", 11762306a36Sopenharmony_ci 8, "write", reg); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return err; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic struct emc6w201_data *emc6w201_update_device(struct device *dev) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct emc6w201_data *data = dev_get_drvdata(dev); 12562306a36Sopenharmony_ci struct i2c_client *client = data->client; 12662306a36Sopenharmony_ci int nr; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci mutex_lock(&data->update_lock); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { 13162306a36Sopenharmony_ci for (nr = 0; nr < 6; nr++) { 13262306a36Sopenharmony_ci data->in[input][nr] = 13362306a36Sopenharmony_ci emc6w201_read8(client, 13462306a36Sopenharmony_ci EMC6W201_REG_IN(nr)); 13562306a36Sopenharmony_ci data->in[min][nr] = 13662306a36Sopenharmony_ci emc6w201_read8(client, 13762306a36Sopenharmony_ci EMC6W201_REG_IN_LOW(nr)); 13862306a36Sopenharmony_ci data->in[max][nr] = 13962306a36Sopenharmony_ci emc6w201_read8(client, 14062306a36Sopenharmony_ci EMC6W201_REG_IN_HIGH(nr)); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci for (nr = 0; nr < 6; nr++) { 14462306a36Sopenharmony_ci data->temp[input][nr] = 14562306a36Sopenharmony_ci emc6w201_read8(client, 14662306a36Sopenharmony_ci EMC6W201_REG_TEMP(nr)); 14762306a36Sopenharmony_ci data->temp[min][nr] = 14862306a36Sopenharmony_ci emc6w201_read8(client, 14962306a36Sopenharmony_ci EMC6W201_REG_TEMP_LOW(nr)); 15062306a36Sopenharmony_ci data->temp[max][nr] = 15162306a36Sopenharmony_ci emc6w201_read8(client, 15262306a36Sopenharmony_ci EMC6W201_REG_TEMP_HIGH(nr)); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci for (nr = 0; nr < 5; nr++) { 15662306a36Sopenharmony_ci data->fan[input][nr] = 15762306a36Sopenharmony_ci emc6w201_read16(client, 15862306a36Sopenharmony_ci EMC6W201_REG_FAN(nr)); 15962306a36Sopenharmony_ci data->fan[min][nr] = 16062306a36Sopenharmony_ci emc6w201_read16(client, 16162306a36Sopenharmony_ci EMC6W201_REG_FAN_MIN(nr)); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci data->last_updated = jiffies; 16562306a36Sopenharmony_ci data->valid = true; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return data; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 17462306a36Sopenharmony_ci * Sysfs callback functions 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const s16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 }; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic ssize_t in_show(struct device *dev, struct device_attribute *devattr, 18062306a36Sopenharmony_ci char *buf) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct emc6w201_data *data = emc6w201_update_device(dev); 18362306a36Sopenharmony_ci int sf = to_sensor_dev_attr_2(devattr)->index; 18462306a36Sopenharmony_ci int nr = to_sensor_dev_attr_2(devattr)->nr; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return sprintf(buf, "%u\n", 18762306a36Sopenharmony_ci (unsigned)data->in[sf][nr] * nominal_mv[nr] / 0xC0); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic ssize_t in_store(struct device *dev, struct device_attribute *devattr, 19162306a36Sopenharmony_ci const char *buf, size_t count) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct emc6w201_data *data = dev_get_drvdata(dev); 19462306a36Sopenharmony_ci struct i2c_client *client = data->client; 19562306a36Sopenharmony_ci int sf = to_sensor_dev_attr_2(devattr)->index; 19662306a36Sopenharmony_ci int nr = to_sensor_dev_attr_2(devattr)->nr; 19762306a36Sopenharmony_ci int err; 19862306a36Sopenharmony_ci long val; 19962306a36Sopenharmony_ci u8 reg; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 20262306a36Sopenharmony_ci if (err < 0) 20362306a36Sopenharmony_ci return err; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci val = clamp_val(val, 0, 255 * nominal_mv[nr] / 192); 20662306a36Sopenharmony_ci val = DIV_ROUND_CLOSEST(val * 192, nominal_mv[nr]); 20762306a36Sopenharmony_ci reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr) 20862306a36Sopenharmony_ci : EMC6W201_REG_IN_HIGH(nr); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 21162306a36Sopenharmony_ci data->in[sf][nr] = val; 21262306a36Sopenharmony_ci err = emc6w201_write8(client, reg, data->in[sf][nr]); 21362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return err < 0 ? err : count; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *devattr, 21962306a36Sopenharmony_ci char *buf) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct emc6w201_data *data = emc6w201_update_device(dev); 22262306a36Sopenharmony_ci int sf = to_sensor_dev_attr_2(devattr)->index; 22362306a36Sopenharmony_ci int nr = to_sensor_dev_attr_2(devattr)->nr; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return sprintf(buf, "%d\n", (int)data->temp[sf][nr] * 1000); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic ssize_t temp_store(struct device *dev, 22962306a36Sopenharmony_ci struct device_attribute *devattr, const char *buf, 23062306a36Sopenharmony_ci size_t count) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct emc6w201_data *data = dev_get_drvdata(dev); 23362306a36Sopenharmony_ci struct i2c_client *client = data->client; 23462306a36Sopenharmony_ci int sf = to_sensor_dev_attr_2(devattr)->index; 23562306a36Sopenharmony_ci int nr = to_sensor_dev_attr_2(devattr)->nr; 23662306a36Sopenharmony_ci int err; 23762306a36Sopenharmony_ci long val; 23862306a36Sopenharmony_ci u8 reg; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 24162306a36Sopenharmony_ci if (err < 0) 24262306a36Sopenharmony_ci return err; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci val = clamp_val(val, -127000, 127000); 24562306a36Sopenharmony_ci val = DIV_ROUND_CLOSEST(val, 1000); 24662306a36Sopenharmony_ci reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr) 24762306a36Sopenharmony_ci : EMC6W201_REG_TEMP_HIGH(nr); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 25062306a36Sopenharmony_ci data->temp[sf][nr] = val; 25162306a36Sopenharmony_ci err = emc6w201_write8(client, reg, data->temp[sf][nr]); 25262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return err < 0 ? err : count; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic ssize_t fan_show(struct device *dev, struct device_attribute *devattr, 25862306a36Sopenharmony_ci char *buf) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct emc6w201_data *data = emc6w201_update_device(dev); 26162306a36Sopenharmony_ci int sf = to_sensor_dev_attr_2(devattr)->index; 26262306a36Sopenharmony_ci int nr = to_sensor_dev_attr_2(devattr)->nr; 26362306a36Sopenharmony_ci unsigned rpm; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (data->fan[sf][nr] == 0 || data->fan[sf][nr] == 0xFFFF) 26662306a36Sopenharmony_ci rpm = 0; 26762306a36Sopenharmony_ci else 26862306a36Sopenharmony_ci rpm = 5400000U / data->fan[sf][nr]; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return sprintf(buf, "%u\n", rpm); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic ssize_t fan_store(struct device *dev, struct device_attribute *devattr, 27462306a36Sopenharmony_ci const char *buf, size_t count) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct emc6w201_data *data = dev_get_drvdata(dev); 27762306a36Sopenharmony_ci struct i2c_client *client = data->client; 27862306a36Sopenharmony_ci int sf = to_sensor_dev_attr_2(devattr)->index; 27962306a36Sopenharmony_ci int nr = to_sensor_dev_attr_2(devattr)->nr; 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci unsigned long val; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci err = kstrtoul(buf, 10, &val); 28462306a36Sopenharmony_ci if (err < 0) 28562306a36Sopenharmony_ci return err; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (val == 0) { 28862306a36Sopenharmony_ci val = 0xFFFF; 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci val = DIV_ROUND_CLOSEST(5400000U, val); 29162306a36Sopenharmony_ci val = clamp_val(val, 0, 0xFFFE); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 29562306a36Sopenharmony_ci data->fan[sf][nr] = val; 29662306a36Sopenharmony_ci err = emc6w201_write16(client, EMC6W201_REG_FAN_MIN(nr), 29762306a36Sopenharmony_ci data->fan[sf][nr]); 29862306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return err < 0 ? err : count; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(in0_input, in, 0, input); 30462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in0_min, in, 0, min); 30562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in0_max, in, 0, max); 30662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(in1_input, in, 1, input); 30762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in1_min, in, 1, min); 30862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in1_max, in, 1, max); 30962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(in2_input, in, 2, input); 31062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in2_min, in, 2, min); 31162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in2_max, in, 2, max); 31262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(in3_input, in, 3, input); 31362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in3_min, in, 3, min); 31462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in3_max, in, 3, max); 31562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(in4_input, in, 4, input); 31662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in4_min, in, 4, min); 31762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in4_max, in, 4, max); 31862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(in5_input, in, 5, input); 31962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in5_min, in, 5, min); 32062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(in5_max, in, 5, max); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, 0, input); 32362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_min, temp, 0, min); 32462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_max, temp, 0, max); 32562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(temp2_input, temp, 1, input); 32662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_min, temp, 1, min); 32762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_max, temp, 1, max); 32862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(temp3_input, temp, 2, input); 32962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_min, temp, 2, min); 33062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_max, temp, 2, max); 33162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(temp4_input, temp, 3, input); 33262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp4_min, temp, 3, min); 33362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp4_max, temp, 3, max); 33462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(temp5_input, temp, 4, input); 33562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp5_min, temp, 4, min); 33662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp5_max, temp, 4, max); 33762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(temp6_input, temp, 5, input); 33862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp6_min, temp, 5, min); 33962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp6_max, temp, 5, max); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(fan1_input, fan, 0, input); 34262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(fan1_min, fan, 0, min); 34362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(fan2_input, fan, 1, input); 34462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(fan2_min, fan, 1, min); 34562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(fan3_input, fan, 2, input); 34662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(fan3_min, fan, 2, min); 34762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(fan4_input, fan, 3, input); 34862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(fan4_min, fan, 3, min); 34962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RO(fan5_input, fan, 4, input); 35062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(fan5_min, fan, 4, min); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic struct attribute *emc6w201_attrs[] = { 35362306a36Sopenharmony_ci &sensor_dev_attr_in0_input.dev_attr.attr, 35462306a36Sopenharmony_ci &sensor_dev_attr_in0_min.dev_attr.attr, 35562306a36Sopenharmony_ci &sensor_dev_attr_in0_max.dev_attr.attr, 35662306a36Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr.attr, 35762306a36Sopenharmony_ci &sensor_dev_attr_in1_min.dev_attr.attr, 35862306a36Sopenharmony_ci &sensor_dev_attr_in1_max.dev_attr.attr, 35962306a36Sopenharmony_ci &sensor_dev_attr_in2_input.dev_attr.attr, 36062306a36Sopenharmony_ci &sensor_dev_attr_in2_min.dev_attr.attr, 36162306a36Sopenharmony_ci &sensor_dev_attr_in2_max.dev_attr.attr, 36262306a36Sopenharmony_ci &sensor_dev_attr_in3_input.dev_attr.attr, 36362306a36Sopenharmony_ci &sensor_dev_attr_in3_min.dev_attr.attr, 36462306a36Sopenharmony_ci &sensor_dev_attr_in3_max.dev_attr.attr, 36562306a36Sopenharmony_ci &sensor_dev_attr_in4_input.dev_attr.attr, 36662306a36Sopenharmony_ci &sensor_dev_attr_in4_min.dev_attr.attr, 36762306a36Sopenharmony_ci &sensor_dev_attr_in4_max.dev_attr.attr, 36862306a36Sopenharmony_ci &sensor_dev_attr_in5_input.dev_attr.attr, 36962306a36Sopenharmony_ci &sensor_dev_attr_in5_min.dev_attr.attr, 37062306a36Sopenharmony_ci &sensor_dev_attr_in5_max.dev_attr.attr, 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 37362306a36Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 37462306a36Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 37562306a36Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, 37662306a36Sopenharmony_ci &sensor_dev_attr_temp2_min.dev_attr.attr, 37762306a36Sopenharmony_ci &sensor_dev_attr_temp2_max.dev_attr.attr, 37862306a36Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr.attr, 37962306a36Sopenharmony_ci &sensor_dev_attr_temp3_min.dev_attr.attr, 38062306a36Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr.attr, 38162306a36Sopenharmony_ci &sensor_dev_attr_temp4_input.dev_attr.attr, 38262306a36Sopenharmony_ci &sensor_dev_attr_temp4_min.dev_attr.attr, 38362306a36Sopenharmony_ci &sensor_dev_attr_temp4_max.dev_attr.attr, 38462306a36Sopenharmony_ci &sensor_dev_attr_temp5_input.dev_attr.attr, 38562306a36Sopenharmony_ci &sensor_dev_attr_temp5_min.dev_attr.attr, 38662306a36Sopenharmony_ci &sensor_dev_attr_temp5_max.dev_attr.attr, 38762306a36Sopenharmony_ci &sensor_dev_attr_temp6_input.dev_attr.attr, 38862306a36Sopenharmony_ci &sensor_dev_attr_temp6_min.dev_attr.attr, 38962306a36Sopenharmony_ci &sensor_dev_attr_temp6_max.dev_attr.attr, 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 39262306a36Sopenharmony_ci &sensor_dev_attr_fan1_min.dev_attr.attr, 39362306a36Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 39462306a36Sopenharmony_ci &sensor_dev_attr_fan2_min.dev_attr.attr, 39562306a36Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr.attr, 39662306a36Sopenharmony_ci &sensor_dev_attr_fan3_min.dev_attr.attr, 39762306a36Sopenharmony_ci &sensor_dev_attr_fan4_input.dev_attr.attr, 39862306a36Sopenharmony_ci &sensor_dev_attr_fan4_min.dev_attr.attr, 39962306a36Sopenharmony_ci &sensor_dev_attr_fan5_input.dev_attr.attr, 40062306a36Sopenharmony_ci &sensor_dev_attr_fan5_min.dev_attr.attr, 40162306a36Sopenharmony_ci NULL 40262306a36Sopenharmony_ci}; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ciATTRIBUTE_GROUPS(emc6w201); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/* 40762306a36Sopenharmony_ci * Driver interface 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 41162306a36Sopenharmony_cistatic int emc6w201_detect(struct i2c_client *client, 41262306a36Sopenharmony_ci struct i2c_board_info *info) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 41562306a36Sopenharmony_ci int company, verstep, config; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 41862306a36Sopenharmony_ci return -ENODEV; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Identification */ 42162306a36Sopenharmony_ci company = i2c_smbus_read_byte_data(client, EMC6W201_REG_COMPANY); 42262306a36Sopenharmony_ci if (company != 0x5C) 42362306a36Sopenharmony_ci return -ENODEV; 42462306a36Sopenharmony_ci verstep = i2c_smbus_read_byte_data(client, EMC6W201_REG_VERSTEP); 42562306a36Sopenharmony_ci if (verstep < 0 || (verstep & 0xF0) != 0xB0) 42662306a36Sopenharmony_ci return -ENODEV; 42762306a36Sopenharmony_ci if ((verstep & 0x0F) > 2) { 42862306a36Sopenharmony_ci dev_dbg(&client->dev, "Unknown EMC6W201 stepping %d\n", 42962306a36Sopenharmony_ci verstep & 0x0F); 43062306a36Sopenharmony_ci return -ENODEV; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* Check configuration */ 43462306a36Sopenharmony_ci config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG); 43562306a36Sopenharmony_ci if (config < 0 || (config & 0xF4) != 0x04) 43662306a36Sopenharmony_ci return -ENODEV; 43762306a36Sopenharmony_ci if (!(config & 0x01)) { 43862306a36Sopenharmony_ci dev_err(&client->dev, "Monitoring not enabled\n"); 43962306a36Sopenharmony_ci return -ENODEV; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci strscpy(info->type, "emc6w201", I2C_NAME_SIZE); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int emc6w201_probe(struct i2c_client *client) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct device *dev = &client->dev; 45062306a36Sopenharmony_ci struct emc6w201_data *data; 45162306a36Sopenharmony_ci struct device *hwmon_dev; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct emc6w201_data), GFP_KERNEL); 45462306a36Sopenharmony_ci if (!data) 45562306a36Sopenharmony_ci return -ENOMEM; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci data->client = client; 45862306a36Sopenharmony_ci mutex_init(&data->update_lock); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 46162306a36Sopenharmony_ci data, 46262306a36Sopenharmony_ci emc6w201_groups); 46362306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic const struct i2c_device_id emc6w201_id[] = { 46762306a36Sopenharmony_ci { "emc6w201", 0 }, 46862306a36Sopenharmony_ci { } 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, emc6w201_id); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic struct i2c_driver emc6w201_driver = { 47362306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 47462306a36Sopenharmony_ci .driver = { 47562306a36Sopenharmony_ci .name = "emc6w201", 47662306a36Sopenharmony_ci }, 47762306a36Sopenharmony_ci .probe = emc6w201_probe, 47862306a36Sopenharmony_ci .id_table = emc6w201_id, 47962306a36Sopenharmony_ci .detect = emc6w201_detect, 48062306a36Sopenharmony_ci .address_list = normal_i2c, 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cimodule_i2c_driver(emc6w201_driver); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ciMODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); 48662306a36Sopenharmony_ciMODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver"); 48762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 488