174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29df7305bSSteve Glendinning /*
3bf0f3a04SGuenter Roeck * emc2103.c - Support for SMSC EMC2103
4bf0f3a04SGuenter Roeck * Copyright (c) 2010 SMSC
59df7305bSSteve Glendinning */
69df7305bSSteve Glendinning
79df7305bSSteve Glendinning #include <linux/module.h>
89df7305bSSteve Glendinning #include <linux/init.h>
99df7305bSSteve Glendinning #include <linux/slab.h>
109df7305bSSteve Glendinning #include <linux/jiffies.h>
119df7305bSSteve Glendinning #include <linux/i2c.h>
129df7305bSSteve Glendinning #include <linux/hwmon.h>
139df7305bSSteve Glendinning #include <linux/hwmon-sysfs.h>
149df7305bSSteve Glendinning #include <linux/err.h>
159df7305bSSteve Glendinning #include <linux/mutex.h>
169df7305bSSteve Glendinning
179df7305bSSteve Glendinning /* Addresses scanned */
189df7305bSSteve Glendinning static const unsigned short normal_i2c[] = { 0x2E, I2C_CLIENT_END };
199df7305bSSteve Glendinning
209df7305bSSteve Glendinning static const u8 REG_TEMP[4] = { 0x00, 0x02, 0x04, 0x06 };
219df7305bSSteve Glendinning static const u8 REG_TEMP_MIN[4] = { 0x3c, 0x38, 0x39, 0x3a };
229df7305bSSteve Glendinning static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 };
239df7305bSSteve Glendinning
249df7305bSSteve Glendinning #define REG_CONF1 0x20
259df7305bSSteve Glendinning #define REG_TEMP_MAX_ALARM 0x24
269df7305bSSteve Glendinning #define REG_TEMP_MIN_ALARM 0x25
279df7305bSSteve Glendinning #define REG_FAN_CONF1 0x42
289df7305bSSteve Glendinning #define REG_FAN_TARGET_LO 0x4c
299df7305bSSteve Glendinning #define REG_FAN_TARGET_HI 0x4d
309df7305bSSteve Glendinning #define REG_FAN_TACH_HI 0x4e
319df7305bSSteve Glendinning #define REG_FAN_TACH_LO 0x4f
329df7305bSSteve Glendinning #define REG_PRODUCT_ID 0xfd
339df7305bSSteve Glendinning #define REG_MFG_ID 0xfe
349df7305bSSteve Glendinning
359df7305bSSteve Glendinning /* equation 4 from datasheet: rpm = (3932160 * multipler) / count */
369df7305bSSteve Glendinning #define FAN_RPM_FACTOR 3932160
379df7305bSSteve Glendinning
38bf0f3a04SGuenter Roeck /*
39bf0f3a04SGuenter Roeck * 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes
409df7305bSSteve Glendinning * in anti-parallel mode, and in this configuration both can be read
419df7305bSSteve Glendinning * independently (so we have 4 temperature inputs). The device can't
429df7305bSSteve Glendinning * detect if it's connected in this mode, so we have to manually enable
439df7305bSSteve Glendinning * it. Default is to leave the device in the state it's already in (-1).
44bf0f3a04SGuenter Roeck * This parameter allows APD mode to be optionally forced on or off
45bf0f3a04SGuenter Roeck */
469df7305bSSteve Glendinning static int apd = -1;
4769116f27SRusty Russell module_param(apd, bint, 0);
4854f0ffc4SDan Carpenter MODULE_PARM_DESC(apd, "Set to zero to disable anti-parallel diode mode");
499df7305bSSteve Glendinning
509df7305bSSteve Glendinning struct temperature {
519df7305bSSteve Glendinning s8 degrees;
529df7305bSSteve Glendinning u8 fraction; /* 0-7 multiples of 0.125 */
539df7305bSSteve Glendinning };
549df7305bSSteve Glendinning
559df7305bSSteve Glendinning struct emc2103_data {
569dd304f8SAxel Lin struct i2c_client *client;
579dd304f8SAxel Lin const struct attribute_group *groups[4];
589df7305bSSteve Glendinning struct mutex update_lock;
599df7305bSSteve Glendinning bool valid; /* registers are valid */
609df7305bSSteve Glendinning bool fan_rpm_control;
619df7305bSSteve Glendinning int temp_count; /* num of temp sensors */
629df7305bSSteve Glendinning unsigned long last_updated; /* in jiffies */
639df7305bSSteve Glendinning struct temperature temp[4]; /* internal + 3 external */
649df7305bSSteve Glendinning s8 temp_min[4]; /* no fractional part */
659df7305bSSteve Glendinning s8 temp_max[4]; /* no fractional part */
669df7305bSSteve Glendinning u8 temp_min_alarm;
679df7305bSSteve Glendinning u8 temp_max_alarm;
689df7305bSSteve Glendinning u8 fan_multiplier;
699df7305bSSteve Glendinning u16 fan_tach;
709df7305bSSteve Glendinning u16 fan_target;
719df7305bSSteve Glendinning };
729df7305bSSteve Glendinning
read_u8_from_i2c(struct i2c_client * client,u8 i2c_reg,u8 * output)739df7305bSSteve Glendinning static int read_u8_from_i2c(struct i2c_client *client, u8 i2c_reg, u8 *output)
749df7305bSSteve Glendinning {
759df7305bSSteve Glendinning int status = i2c_smbus_read_byte_data(client, i2c_reg);
769df7305bSSteve Glendinning if (status < 0) {
779df7305bSSteve Glendinning dev_warn(&client->dev, "reg 0x%02x, err %d\n",
789df7305bSSteve Glendinning i2c_reg, status);
799df7305bSSteve Glendinning } else {
809df7305bSSteve Glendinning *output = status;
819df7305bSSteve Glendinning }
829df7305bSSteve Glendinning return status;
839df7305bSSteve Glendinning }
849df7305bSSteve Glendinning
read_temp_from_i2c(struct i2c_client * client,u8 i2c_reg,struct temperature * temp)859df7305bSSteve Glendinning static void read_temp_from_i2c(struct i2c_client *client, u8 i2c_reg,
869df7305bSSteve Glendinning struct temperature *temp)
879df7305bSSteve Glendinning {
889df7305bSSteve Glendinning u8 degrees, fractional;
899df7305bSSteve Glendinning
909df7305bSSteve Glendinning if (read_u8_from_i2c(client, i2c_reg, °rees) < 0)
919df7305bSSteve Glendinning return;
929df7305bSSteve Glendinning
939df7305bSSteve Glendinning if (read_u8_from_i2c(client, i2c_reg + 1, &fractional) < 0)
949df7305bSSteve Glendinning return;
959df7305bSSteve Glendinning
969df7305bSSteve Glendinning temp->degrees = degrees;
979df7305bSSteve Glendinning temp->fraction = (fractional & 0xe0) >> 5;
989df7305bSSteve Glendinning }
999df7305bSSteve Glendinning
read_fan_from_i2c(struct i2c_client * client,u16 * output,u8 hi_addr,u8 lo_addr)1009df7305bSSteve Glendinning static void read_fan_from_i2c(struct i2c_client *client, u16 *output,
1019df7305bSSteve Glendinning u8 hi_addr, u8 lo_addr)
1029df7305bSSteve Glendinning {
1039df7305bSSteve Glendinning u8 high_byte, lo_byte;
1049df7305bSSteve Glendinning
1059df7305bSSteve Glendinning if (read_u8_from_i2c(client, hi_addr, &high_byte) < 0)
1069df7305bSSteve Glendinning return;
1079df7305bSSteve Glendinning
1089df7305bSSteve Glendinning if (read_u8_from_i2c(client, lo_addr, &lo_byte) < 0)
1099df7305bSSteve Glendinning return;
1109df7305bSSteve Glendinning
1119df7305bSSteve Glendinning *output = ((u16)high_byte << 5) | (lo_byte >> 3);
1129df7305bSSteve Glendinning }
1139df7305bSSteve Glendinning
write_fan_target_to_i2c(struct i2c_client * client,u16 new_target)1149df7305bSSteve Glendinning static void write_fan_target_to_i2c(struct i2c_client *client, u16 new_target)
1159df7305bSSteve Glendinning {
1169df7305bSSteve Glendinning u8 high_byte = (new_target & 0x1fe0) >> 5;
1179df7305bSSteve Glendinning u8 low_byte = (new_target & 0x001f) << 3;
1189df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_FAN_TARGET_LO, low_byte);
1199df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_FAN_TARGET_HI, high_byte);
1209df7305bSSteve Glendinning }
1219df7305bSSteve Glendinning
read_fan_config_from_i2c(struct i2c_client * client)1229df7305bSSteve Glendinning static void read_fan_config_from_i2c(struct i2c_client *client)
1239df7305bSSteve Glendinning
1249df7305bSSteve Glendinning {
1259df7305bSSteve Glendinning struct emc2103_data *data = i2c_get_clientdata(client);
1269df7305bSSteve Glendinning u8 conf1;
1279df7305bSSteve Glendinning
1289df7305bSSteve Glendinning if (read_u8_from_i2c(client, REG_FAN_CONF1, &conf1) < 0)
1299df7305bSSteve Glendinning return;
1309df7305bSSteve Glendinning
1319df7305bSSteve Glendinning data->fan_multiplier = 1 << ((conf1 & 0x60) >> 5);
1329df7305bSSteve Glendinning data->fan_rpm_control = (conf1 & 0x80) != 0;
1339df7305bSSteve Glendinning }
1349df7305bSSteve Glendinning
emc2103_update_device(struct device * dev)1359df7305bSSteve Glendinning static struct emc2103_data *emc2103_update_device(struct device *dev)
1369df7305bSSteve Glendinning {
1379dd304f8SAxel Lin struct emc2103_data *data = dev_get_drvdata(dev);
1389dd304f8SAxel Lin struct i2c_client *client = data->client;
1399df7305bSSteve Glendinning
1409df7305bSSteve Glendinning mutex_lock(&data->update_lock);
1419df7305bSSteve Glendinning
1429df7305bSSteve Glendinning if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1439df7305bSSteve Glendinning || !data->valid) {
1449df7305bSSteve Glendinning int i;
1459df7305bSSteve Glendinning
1469df7305bSSteve Glendinning for (i = 0; i < data->temp_count; i++) {
1479df7305bSSteve Glendinning read_temp_from_i2c(client, REG_TEMP[i], &data->temp[i]);
1489df7305bSSteve Glendinning read_u8_from_i2c(client, REG_TEMP_MIN[i],
1499df7305bSSteve Glendinning &data->temp_min[i]);
1509df7305bSSteve Glendinning read_u8_from_i2c(client, REG_TEMP_MAX[i],
1519df7305bSSteve Glendinning &data->temp_max[i]);
1529df7305bSSteve Glendinning }
1539df7305bSSteve Glendinning
1549df7305bSSteve Glendinning read_u8_from_i2c(client, REG_TEMP_MIN_ALARM,
1559df7305bSSteve Glendinning &data->temp_min_alarm);
1569df7305bSSteve Glendinning read_u8_from_i2c(client, REG_TEMP_MAX_ALARM,
1579df7305bSSteve Glendinning &data->temp_max_alarm);
1589df7305bSSteve Glendinning
1599df7305bSSteve Glendinning read_fan_from_i2c(client, &data->fan_tach,
1609df7305bSSteve Glendinning REG_FAN_TACH_HI, REG_FAN_TACH_LO);
1619df7305bSSteve Glendinning read_fan_from_i2c(client, &data->fan_target,
1629df7305bSSteve Glendinning REG_FAN_TARGET_HI, REG_FAN_TARGET_LO);
1639df7305bSSteve Glendinning read_fan_config_from_i2c(client);
1649df7305bSSteve Glendinning
1659df7305bSSteve Glendinning data->last_updated = jiffies;
1669df7305bSSteve Glendinning data->valid = true;
1679df7305bSSteve Glendinning }
1689df7305bSSteve Glendinning
1699df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
1709df7305bSSteve Glendinning
1719df7305bSSteve Glendinning return data;
1729df7305bSSteve Glendinning }
1739df7305bSSteve Glendinning
1749df7305bSSteve Glendinning static ssize_t
temp_show(struct device * dev,struct device_attribute * da,char * buf)17594bf70daSGuenter Roeck temp_show(struct device *dev, struct device_attribute *da, char *buf)
1769df7305bSSteve Glendinning {
1779df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
1789df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
1799df7305bSSteve Glendinning int millidegrees = data->temp[nr].degrees * 1000
1809df7305bSSteve Glendinning + data->temp[nr].fraction * 125;
1819df7305bSSteve Glendinning return sprintf(buf, "%d\n", millidegrees);
1829df7305bSSteve Glendinning }
1839df7305bSSteve Glendinning
1849df7305bSSteve Glendinning static ssize_t
temp_min_show(struct device * dev,struct device_attribute * da,char * buf)18594bf70daSGuenter Roeck temp_min_show(struct device *dev, struct device_attribute *da, char *buf)
1869df7305bSSteve Glendinning {
1879df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
1889df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
1899df7305bSSteve Glendinning int millidegrees = data->temp_min[nr] * 1000;
1909df7305bSSteve Glendinning return sprintf(buf, "%d\n", millidegrees);
1919df7305bSSteve Glendinning }
1929df7305bSSteve Glendinning
1939df7305bSSteve Glendinning static ssize_t
temp_max_show(struct device * dev,struct device_attribute * da,char * buf)19494bf70daSGuenter Roeck temp_max_show(struct device *dev, struct device_attribute *da, char *buf)
1959df7305bSSteve Glendinning {
1969df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
1979df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
1989df7305bSSteve Glendinning int millidegrees = data->temp_max[nr] * 1000;
1999df7305bSSteve Glendinning return sprintf(buf, "%d\n", millidegrees);
2009df7305bSSteve Glendinning }
2019df7305bSSteve Glendinning
2029df7305bSSteve Glendinning static ssize_t
temp_fault_show(struct device * dev,struct device_attribute * da,char * buf)20394bf70daSGuenter Roeck temp_fault_show(struct device *dev, struct device_attribute *da, char *buf)
2049df7305bSSteve Glendinning {
2059df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
2069df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
2079df7305bSSteve Glendinning bool fault = (data->temp[nr].degrees == -128);
2089df7305bSSteve Glendinning return sprintf(buf, "%d\n", fault ? 1 : 0);
2099df7305bSSteve Glendinning }
2109df7305bSSteve Glendinning
2119df7305bSSteve Glendinning static ssize_t
temp_min_alarm_show(struct device * dev,struct device_attribute * da,char * buf)21294bf70daSGuenter Roeck temp_min_alarm_show(struct device *dev, struct device_attribute *da,
21394bf70daSGuenter Roeck char *buf)
2149df7305bSSteve Glendinning {
2159df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
2169df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
2179df7305bSSteve Glendinning bool alarm = data->temp_min_alarm & (1 << nr);
2189df7305bSSteve Glendinning return sprintf(buf, "%d\n", alarm ? 1 : 0);
2199df7305bSSteve Glendinning }
2209df7305bSSteve Glendinning
2219df7305bSSteve Glendinning static ssize_t
temp_max_alarm_show(struct device * dev,struct device_attribute * da,char * buf)22294bf70daSGuenter Roeck temp_max_alarm_show(struct device *dev, struct device_attribute *da,
22394bf70daSGuenter Roeck char *buf)
2249df7305bSSteve Glendinning {
2259df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
2269df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
2279df7305bSSteve Glendinning bool alarm = data->temp_max_alarm & (1 << nr);
2289df7305bSSteve Glendinning return sprintf(buf, "%d\n", alarm ? 1 : 0);
2299df7305bSSteve Glendinning }
2309df7305bSSteve Glendinning
temp_min_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)23194bf70daSGuenter Roeck static ssize_t temp_min_store(struct device *dev, struct device_attribute *da,
2329df7305bSSteve Glendinning const char *buf, size_t count)
2339df7305bSSteve Glendinning {
2349df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
2359dd304f8SAxel Lin struct emc2103_data *data = dev_get_drvdata(dev);
2369dd304f8SAxel Lin struct i2c_client *client = data->client;
2379df7305bSSteve Glendinning long val;
2389df7305bSSteve Glendinning
239179c4fdbSFrans Meulenbroeks int result = kstrtol(buf, 10, &val);
2409df7305bSSteve Glendinning if (result < 0)
2411a3abbd0SSachin Kamat return result;
2429df7305bSSteve Glendinning
243ca1b10b8SGuenter Roeck val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000);
2449df7305bSSteve Glendinning
2459df7305bSSteve Glendinning mutex_lock(&data->update_lock);
2469df7305bSSteve Glendinning data->temp_min[nr] = val;
2479df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_TEMP_MIN[nr], val);
2489df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
2499df7305bSSteve Glendinning
2509df7305bSSteve Glendinning return count;
2519df7305bSSteve Glendinning }
2529df7305bSSteve Glendinning
temp_max_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)25394bf70daSGuenter Roeck static ssize_t temp_max_store(struct device *dev, struct device_attribute *da,
2549df7305bSSteve Glendinning const char *buf, size_t count)
2559df7305bSSteve Glendinning {
2569df7305bSSteve Glendinning int nr = to_sensor_dev_attr(da)->index;
2579dd304f8SAxel Lin struct emc2103_data *data = dev_get_drvdata(dev);
2589dd304f8SAxel Lin struct i2c_client *client = data->client;
2599df7305bSSteve Glendinning long val;
2609df7305bSSteve Glendinning
261179c4fdbSFrans Meulenbroeks int result = kstrtol(buf, 10, &val);
2629df7305bSSteve Glendinning if (result < 0)
2631a3abbd0SSachin Kamat return result;
2649df7305bSSteve Glendinning
265ca1b10b8SGuenter Roeck val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000);
2669df7305bSSteve Glendinning
2679df7305bSSteve Glendinning mutex_lock(&data->update_lock);
2689df7305bSSteve Glendinning data->temp_max[nr] = val;
2699df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_TEMP_MAX[nr], val);
2709df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
2719df7305bSSteve Glendinning
2729df7305bSSteve Glendinning return count;
2739df7305bSSteve Glendinning }
2749df7305bSSteve Glendinning
2759df7305bSSteve Glendinning static ssize_t
fan1_input_show(struct device * dev,struct device_attribute * da,char * buf)2764cd0183dSJulia Lawall fan1_input_show(struct device *dev, struct device_attribute *da, char *buf)
2779df7305bSSteve Glendinning {
2789df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
2799df7305bSSteve Glendinning int rpm = 0;
2809df7305bSSteve Glendinning if (data->fan_tach != 0)
2819df7305bSSteve Glendinning rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach;
2829df7305bSSteve Glendinning return sprintf(buf, "%d\n", rpm);
2839df7305bSSteve Glendinning }
2849df7305bSSteve Glendinning
2859df7305bSSteve Glendinning static ssize_t
fan1_div_show(struct device * dev,struct device_attribute * da,char * buf)2864cd0183dSJulia Lawall fan1_div_show(struct device *dev, struct device_attribute *da, char *buf)
2879df7305bSSteve Glendinning {
2889df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
2899df7305bSSteve Glendinning int fan_div = 8 / data->fan_multiplier;
2909df7305bSSteve Glendinning return sprintf(buf, "%d\n", fan_div);
2919df7305bSSteve Glendinning }
2929df7305bSSteve Glendinning
293bf0f3a04SGuenter Roeck /*
294bf0f3a04SGuenter Roeck * Note: we also update the fan target here, because its value is
295bf0f3a04SGuenter Roeck * determined in part by the fan clock divider. This follows the principle
296bf0f3a04SGuenter Roeck * of least surprise; the user doesn't expect the fan target to change just
297bf0f3a04SGuenter Roeck * because the divider changed.
298bf0f3a04SGuenter Roeck */
fan1_div_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)2994cd0183dSJulia Lawall static ssize_t fan1_div_store(struct device *dev, struct device_attribute *da,
3009df7305bSSteve Glendinning const char *buf, size_t count)
3019df7305bSSteve Glendinning {
3029df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
3039dd304f8SAxel Lin struct i2c_client *client = data->client;
3049df7305bSSteve Glendinning int new_range_bits, old_div = 8 / data->fan_multiplier;
3059df7305bSSteve Glendinning long new_div;
3069df7305bSSteve Glendinning
307179c4fdbSFrans Meulenbroeks int status = kstrtol(buf, 10, &new_div);
3089df7305bSSteve Glendinning if (status < 0)
3091a3abbd0SSachin Kamat return status;
3109df7305bSSteve Glendinning
3119df7305bSSteve Glendinning if (new_div == old_div) /* No change */
3129df7305bSSteve Glendinning return count;
3139df7305bSSteve Glendinning
3149df7305bSSteve Glendinning switch (new_div) {
3159df7305bSSteve Glendinning case 1:
3169df7305bSSteve Glendinning new_range_bits = 3;
3179df7305bSSteve Glendinning break;
3189df7305bSSteve Glendinning case 2:
3199df7305bSSteve Glendinning new_range_bits = 2;
3209df7305bSSteve Glendinning break;
3219df7305bSSteve Glendinning case 4:
3229df7305bSSteve Glendinning new_range_bits = 1;
3239df7305bSSteve Glendinning break;
3249df7305bSSteve Glendinning case 8:
3259df7305bSSteve Glendinning new_range_bits = 0;
3269df7305bSSteve Glendinning break;
3279df7305bSSteve Glendinning default:
3289df7305bSSteve Glendinning return -EINVAL;
3299df7305bSSteve Glendinning }
3309df7305bSSteve Glendinning
3319df7305bSSteve Glendinning mutex_lock(&data->update_lock);
3329df7305bSSteve Glendinning
3339df7305bSSteve Glendinning status = i2c_smbus_read_byte_data(client, REG_FAN_CONF1);
3349df7305bSSteve Glendinning if (status < 0) {
3359df7305bSSteve Glendinning dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
3369df7305bSSteve Glendinning REG_FAN_CONF1, status);
3379df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
3389bf3babfSGuenter Roeck return status;
3399df7305bSSteve Glendinning }
3409df7305bSSteve Glendinning status &= 0x9F;
3419df7305bSSteve Glendinning status |= (new_range_bits << 5);
3429df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_FAN_CONF1, status);
3439df7305bSSteve Glendinning
3449df7305bSSteve Glendinning data->fan_multiplier = 8 / new_div;
3459df7305bSSteve Glendinning
3469df7305bSSteve Glendinning /* update fan target if high byte is not disabled */
3479df7305bSSteve Glendinning if ((data->fan_target & 0x1fe0) != 0x1fe0) {
3489df7305bSSteve Glendinning u16 new_target = (data->fan_target * old_div) / new_div;
3499df7305bSSteve Glendinning data->fan_target = min(new_target, (u16)0x1fff);
3509df7305bSSteve Glendinning write_fan_target_to_i2c(client, data->fan_target);
3519df7305bSSteve Glendinning }
3529df7305bSSteve Glendinning
3539df7305bSSteve Glendinning /* invalidate data to force re-read from hardware */
3549df7305bSSteve Glendinning data->valid = false;
3559df7305bSSteve Glendinning
3569df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
3579df7305bSSteve Glendinning return count;
3589df7305bSSteve Glendinning }
3599df7305bSSteve Glendinning
3609df7305bSSteve Glendinning static ssize_t
fan1_target_show(struct device * dev,struct device_attribute * da,char * buf)3614cd0183dSJulia Lawall fan1_target_show(struct device *dev, struct device_attribute *da, char *buf)
3629df7305bSSteve Glendinning {
3639df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
3649df7305bSSteve Glendinning int rpm = 0;
3659df7305bSSteve Glendinning
3669df7305bSSteve Glendinning /* high byte of 0xff indicates disabled so return 0 */
3679df7305bSSteve Glendinning if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0))
3689df7305bSSteve Glendinning rpm = (FAN_RPM_FACTOR * data->fan_multiplier)
3699df7305bSSteve Glendinning / data->fan_target;
3709df7305bSSteve Glendinning
3719df7305bSSteve Glendinning return sprintf(buf, "%d\n", rpm);
3729df7305bSSteve Glendinning }
3739df7305bSSteve Glendinning
fan1_target_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)3744cd0183dSJulia Lawall static ssize_t fan1_target_store(struct device *dev,
3754cd0183dSJulia Lawall struct device_attribute *da, const char *buf,
3764cd0183dSJulia Lawall size_t count)
3779df7305bSSteve Glendinning {
3789df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
3799dd304f8SAxel Lin struct i2c_client *client = data->client;
380f6c2dd20SGuenter Roeck unsigned long rpm_target;
3819df7305bSSteve Glendinning
382f6c2dd20SGuenter Roeck int result = kstrtoul(buf, 10, &rpm_target);
3839df7305bSSteve Glendinning if (result < 0)
3841a3abbd0SSachin Kamat return result;
3859df7305bSSteve Glendinning
3869df7305bSSteve Glendinning /* Datasheet states 16384 as maximum RPM target (table 3.2) */
387f6c2dd20SGuenter Roeck rpm_target = clamp_val(rpm_target, 0, 16384);
3889df7305bSSteve Glendinning
3899df7305bSSteve Glendinning mutex_lock(&data->update_lock);
3909df7305bSSteve Glendinning
3919df7305bSSteve Glendinning if (rpm_target == 0)
3929df7305bSSteve Glendinning data->fan_target = 0x1fff;
3939df7305bSSteve Glendinning else
3942a844c14SGuenter Roeck data->fan_target = clamp_val(
3959df7305bSSteve Glendinning (FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target,
3969df7305bSSteve Glendinning 0, 0x1fff);
3979df7305bSSteve Glendinning
3989df7305bSSteve Glendinning write_fan_target_to_i2c(client, data->fan_target);
3999df7305bSSteve Glendinning
4009df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
4019df7305bSSteve Glendinning return count;
4029df7305bSSteve Glendinning }
4039df7305bSSteve Glendinning
4049df7305bSSteve Glendinning static ssize_t
fan1_fault_show(struct device * dev,struct device_attribute * da,char * buf)4054cd0183dSJulia Lawall fan1_fault_show(struct device *dev, struct device_attribute *da, char *buf)
4069df7305bSSteve Glendinning {
4079df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
4089df7305bSSteve Glendinning bool fault = ((data->fan_tach & 0x1fe0) == 0x1fe0);
4099df7305bSSteve Glendinning return sprintf(buf, "%d\n", fault ? 1 : 0);
4109df7305bSSteve Glendinning }
4119df7305bSSteve Glendinning
4129df7305bSSteve Glendinning static ssize_t
pwm1_enable_show(struct device * dev,struct device_attribute * da,char * buf)4134cd0183dSJulia Lawall pwm1_enable_show(struct device *dev, struct device_attribute *da, char *buf)
4149df7305bSSteve Glendinning {
4159df7305bSSteve Glendinning struct emc2103_data *data = emc2103_update_device(dev);
4169df7305bSSteve Glendinning return sprintf(buf, "%d\n", data->fan_rpm_control ? 3 : 0);
4179df7305bSSteve Glendinning }
4189df7305bSSteve Glendinning
pwm1_enable_store(struct device * dev,struct device_attribute * da,const char * buf,size_t count)4194cd0183dSJulia Lawall static ssize_t pwm1_enable_store(struct device *dev,
4204cd0183dSJulia Lawall struct device_attribute *da, const char *buf,
4214cd0183dSJulia Lawall size_t count)
4229df7305bSSteve Glendinning {
4239dd304f8SAxel Lin struct emc2103_data *data = dev_get_drvdata(dev);
4249dd304f8SAxel Lin struct i2c_client *client = data->client;
4259df7305bSSteve Glendinning long new_value;
4269df7305bSSteve Glendinning u8 conf_reg;
4279df7305bSSteve Glendinning
428179c4fdbSFrans Meulenbroeks int result = kstrtol(buf, 10, &new_value);
4299df7305bSSteve Glendinning if (result < 0)
4301a3abbd0SSachin Kamat return result;
4319df7305bSSteve Glendinning
4329df7305bSSteve Glendinning mutex_lock(&data->update_lock);
4339df7305bSSteve Glendinning switch (new_value) {
4349df7305bSSteve Glendinning case 0:
4359df7305bSSteve Glendinning data->fan_rpm_control = false;
4369df7305bSSteve Glendinning break;
4379df7305bSSteve Glendinning case 3:
4389df7305bSSteve Glendinning data->fan_rpm_control = true;
4399df7305bSSteve Glendinning break;
4409df7305bSSteve Glendinning default:
4412355375eSGuenter Roeck count = -EINVAL;
4422355375eSGuenter Roeck goto err;
4439df7305bSSteve Glendinning }
4449df7305bSSteve Glendinning
4452355375eSGuenter Roeck result = read_u8_from_i2c(client, REG_FAN_CONF1, &conf_reg);
44614b0e83dSVishwas M if (result < 0) {
4472355375eSGuenter Roeck count = result;
4482355375eSGuenter Roeck goto err;
4492355375eSGuenter Roeck }
4509df7305bSSteve Glendinning
4519df7305bSSteve Glendinning if (data->fan_rpm_control)
4529df7305bSSteve Glendinning conf_reg |= 0x80;
4539df7305bSSteve Glendinning else
4549df7305bSSteve Glendinning conf_reg &= ~0x80;
4559df7305bSSteve Glendinning
4569df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_FAN_CONF1, conf_reg);
4572355375eSGuenter Roeck err:
4589df7305bSSteve Glendinning mutex_unlock(&data->update_lock);
4599df7305bSSteve Glendinning return count;
4609df7305bSSteve Glendinning }
4619df7305bSSteve Glendinning
46294bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
46394bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
46494bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
46594bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
46694bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, temp_min_alarm, 0);
46794bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, temp_max_alarm, 0);
4689df7305bSSteve Glendinning
46994bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
47094bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
47194bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
47294bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
47394bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, temp_min_alarm, 1);
47494bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, temp_max_alarm, 1);
4759df7305bSSteve Glendinning
47694bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
47794bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2);
47894bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2);
47994bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2);
48094bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_min_alarm, temp_min_alarm, 2);
48194bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, temp_max_alarm, 2);
4829df7305bSSteve Glendinning
48394bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3);
48494bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp4_min, temp_min, 3);
48594bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp4_max, temp_max, 3);
48694bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3);
48794bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_min_alarm, temp_min_alarm, 3);
48894bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_max_alarm, temp_max_alarm, 3);
4899df7305bSSteve Glendinning
4904cd0183dSJulia Lawall static DEVICE_ATTR_RO(fan1_input);
4914cd0183dSJulia Lawall static DEVICE_ATTR_RW(fan1_div);
4924cd0183dSJulia Lawall static DEVICE_ATTR_RW(fan1_target);
4934cd0183dSJulia Lawall static DEVICE_ATTR_RO(fan1_fault);
4949df7305bSSteve Glendinning
4954cd0183dSJulia Lawall static DEVICE_ATTR_RW(pwm1_enable);
4969df7305bSSteve Glendinning
4979df7305bSSteve Glendinning /* sensors present on all models */
4989df7305bSSteve Glendinning static struct attribute *emc2103_attributes[] = {
4999df7305bSSteve Glendinning &sensor_dev_attr_temp1_input.dev_attr.attr,
5009df7305bSSteve Glendinning &sensor_dev_attr_temp1_min.dev_attr.attr,
5019df7305bSSteve Glendinning &sensor_dev_attr_temp1_max.dev_attr.attr,
5029df7305bSSteve Glendinning &sensor_dev_attr_temp1_fault.dev_attr.attr,
5039df7305bSSteve Glendinning &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
5049df7305bSSteve Glendinning &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
5059df7305bSSteve Glendinning &sensor_dev_attr_temp2_input.dev_attr.attr,
5069df7305bSSteve Glendinning &sensor_dev_attr_temp2_min.dev_attr.attr,
5079df7305bSSteve Glendinning &sensor_dev_attr_temp2_max.dev_attr.attr,
5089df7305bSSteve Glendinning &sensor_dev_attr_temp2_fault.dev_attr.attr,
5099df7305bSSteve Glendinning &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
5109df7305bSSteve Glendinning &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
5119df7305bSSteve Glendinning &dev_attr_fan1_input.attr,
5129df7305bSSteve Glendinning &dev_attr_fan1_div.attr,
5139df7305bSSteve Glendinning &dev_attr_fan1_target.attr,
5149df7305bSSteve Glendinning &dev_attr_fan1_fault.attr,
5159df7305bSSteve Glendinning &dev_attr_pwm1_enable.attr,
5169df7305bSSteve Glendinning NULL
5179df7305bSSteve Glendinning };
5189df7305bSSteve Glendinning
5199df7305bSSteve Glendinning /* extra temperature sensors only present on 2103-2 and 2103-4 */
5209df7305bSSteve Glendinning static struct attribute *emc2103_attributes_temp3[] = {
5219df7305bSSteve Glendinning &sensor_dev_attr_temp3_input.dev_attr.attr,
5229df7305bSSteve Glendinning &sensor_dev_attr_temp3_min.dev_attr.attr,
5239df7305bSSteve Glendinning &sensor_dev_attr_temp3_max.dev_attr.attr,
5249df7305bSSteve Glendinning &sensor_dev_attr_temp3_fault.dev_attr.attr,
5259df7305bSSteve Glendinning &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
5269df7305bSSteve Glendinning &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
5279df7305bSSteve Glendinning NULL
5289df7305bSSteve Glendinning };
5299df7305bSSteve Glendinning
5309df7305bSSteve Glendinning /* extra temperature sensors only present on 2103-2 and 2103-4 in APD mode */
5319df7305bSSteve Glendinning static struct attribute *emc2103_attributes_temp4[] = {
5329df7305bSSteve Glendinning &sensor_dev_attr_temp4_input.dev_attr.attr,
5339df7305bSSteve Glendinning &sensor_dev_attr_temp4_min.dev_attr.attr,
5349df7305bSSteve Glendinning &sensor_dev_attr_temp4_max.dev_attr.attr,
5359df7305bSSteve Glendinning &sensor_dev_attr_temp4_fault.dev_attr.attr,
5369df7305bSSteve Glendinning &sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
5379df7305bSSteve Glendinning &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
5389df7305bSSteve Glendinning NULL
5399df7305bSSteve Glendinning };
5409df7305bSSteve Glendinning
5419df7305bSSteve Glendinning static const struct attribute_group emc2103_group = {
5429df7305bSSteve Glendinning .attrs = emc2103_attributes,
5439df7305bSSteve Glendinning };
5449df7305bSSteve Glendinning
5459df7305bSSteve Glendinning static const struct attribute_group emc2103_temp3_group = {
5469df7305bSSteve Glendinning .attrs = emc2103_attributes_temp3,
5479df7305bSSteve Glendinning };
5489df7305bSSteve Glendinning
5499df7305bSSteve Glendinning static const struct attribute_group emc2103_temp4_group = {
5509df7305bSSteve Glendinning .attrs = emc2103_attributes_temp4,
5519df7305bSSteve Glendinning };
5529df7305bSSteve Glendinning
5539df7305bSSteve Glendinning static int
emc2103_probe(struct i2c_client * client)5549bf5dd8bSStephen Kitt emc2103_probe(struct i2c_client *client)
5559df7305bSSteve Glendinning {
5569df7305bSSteve Glendinning struct emc2103_data *data;
5579dd304f8SAxel Lin struct device *hwmon_dev;
5589dd304f8SAxel Lin int status, idx = 0;
5599df7305bSSteve Glendinning
5609df7305bSSteve Glendinning if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
5619df7305bSSteve Glendinning return -EIO;
5629df7305bSSteve Glendinning
56359da32d8SGuenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
56459da32d8SGuenter Roeck GFP_KERNEL);
5659df7305bSSteve Glendinning if (!data)
5669df7305bSSteve Glendinning return -ENOMEM;
5679df7305bSSteve Glendinning
5689df7305bSSteve Glendinning i2c_set_clientdata(client, data);
5699dd304f8SAxel Lin data->client = client;
5709df7305bSSteve Glendinning mutex_init(&data->update_lock);
5719df7305bSSteve Glendinning
5729df7305bSSteve Glendinning /* 2103-2 and 2103-4 have 3 external diodes, 2103-1 has 1 */
5739df7305bSSteve Glendinning status = i2c_smbus_read_byte_data(client, REG_PRODUCT_ID);
5749df7305bSSteve Glendinning if (status == 0x24) {
5759df7305bSSteve Glendinning /* 2103-1 only has 1 external diode */
5769df7305bSSteve Glendinning data->temp_count = 2;
5779df7305bSSteve Glendinning } else {
5789df7305bSSteve Glendinning /* 2103-2 and 2103-4 have 3 or 4 external diodes */
5799df7305bSSteve Glendinning status = i2c_smbus_read_byte_data(client, REG_CONF1);
5809df7305bSSteve Glendinning if (status < 0) {
5819df7305bSSteve Glendinning dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
5829df7305bSSteve Glendinning status);
58359da32d8SGuenter Roeck return status;
5849df7305bSSteve Glendinning }
5859df7305bSSteve Glendinning
5869df7305bSSteve Glendinning /* detect current state of hardware */
5879df7305bSSteve Glendinning data->temp_count = (status & 0x01) ? 4 : 3;
5889df7305bSSteve Glendinning
5899df7305bSSteve Glendinning /* force APD state if module parameter is set */
5909df7305bSSteve Glendinning if (apd == 0) {
5919df7305bSSteve Glendinning /* force APD mode off */
5929df7305bSSteve Glendinning data->temp_count = 3;
5939df7305bSSteve Glendinning status &= ~(0x01);
5949df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_CONF1, status);
5959df7305bSSteve Glendinning } else if (apd == 1) {
5969df7305bSSteve Glendinning /* force APD mode on */
5979df7305bSSteve Glendinning data->temp_count = 4;
5989df7305bSSteve Glendinning status |= 0x01;
5999df7305bSSteve Glendinning i2c_smbus_write_byte_data(client, REG_CONF1, status);
6009df7305bSSteve Glendinning }
6019df7305bSSteve Glendinning }
6029df7305bSSteve Glendinning
6039dd304f8SAxel Lin /* sysfs hooks */
6049dd304f8SAxel Lin data->groups[idx++] = &emc2103_group;
6059dd304f8SAxel Lin if (data->temp_count >= 3)
6069dd304f8SAxel Lin data->groups[idx++] = &emc2103_temp3_group;
6079dd304f8SAxel Lin if (data->temp_count == 4)
6089dd304f8SAxel Lin data->groups[idx++] = &emc2103_temp4_group;
6099df7305bSSteve Glendinning
6109dd304f8SAxel Lin hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
6119dd304f8SAxel Lin client->name, data,
6129dd304f8SAxel Lin data->groups);
6139dd304f8SAxel Lin if (IS_ERR(hwmon_dev))
6149dd304f8SAxel Lin return PTR_ERR(hwmon_dev);
6159df7305bSSteve Glendinning
6169df7305bSSteve Glendinning dev_info(&client->dev, "%s: sensor '%s'\n",
6179dd304f8SAxel Lin dev_name(hwmon_dev), client->name);
6189df7305bSSteve Glendinning
6199df7305bSSteve Glendinning return 0;
6209df7305bSSteve Glendinning }
6219df7305bSSteve Glendinning
6229df7305bSSteve Glendinning static const struct i2c_device_id emc2103_ids[] = {
623*d8a66f36SUwe Kleine-König { "emc2103" },
6249df7305bSSteve Glendinning { /* LIST END */ }
6259df7305bSSteve Glendinning };
6269df7305bSSteve Glendinning MODULE_DEVICE_TABLE(i2c, emc2103_ids);
6279df7305bSSteve Glendinning
6289df7305bSSteve Glendinning /* Return 0 if detection is successful, -ENODEV otherwise */
6299df7305bSSteve Glendinning static int
emc2103_detect(struct i2c_client * new_client,struct i2c_board_info * info)6309df7305bSSteve Glendinning emc2103_detect(struct i2c_client *new_client, struct i2c_board_info *info)
6319df7305bSSteve Glendinning {
6329df7305bSSteve Glendinning struct i2c_adapter *adapter = new_client->adapter;
6339df7305bSSteve Glendinning int manufacturer, product;
6349df7305bSSteve Glendinning
6359df7305bSSteve Glendinning if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
6369df7305bSSteve Glendinning return -ENODEV;
6379df7305bSSteve Glendinning
6389df7305bSSteve Glendinning manufacturer = i2c_smbus_read_byte_data(new_client, REG_MFG_ID);
6399df7305bSSteve Glendinning if (manufacturer != 0x5D)
6409df7305bSSteve Glendinning return -ENODEV;
6419df7305bSSteve Glendinning
6429df7305bSSteve Glendinning product = i2c_smbus_read_byte_data(new_client, REG_PRODUCT_ID);
6439df7305bSSteve Glendinning if ((product != 0x24) && (product != 0x26))
6449df7305bSSteve Glendinning return -ENODEV;
6459df7305bSSteve Glendinning
646f2f394dbSWolfram Sang strscpy(info->type, "emc2103", I2C_NAME_SIZE);
6479df7305bSSteve Glendinning
6489df7305bSSteve Glendinning return 0;
6499df7305bSSteve Glendinning }
6509df7305bSSteve Glendinning
6519df7305bSSteve Glendinning static struct i2c_driver emc2103_driver = {
6529df7305bSSteve Glendinning .class = I2C_CLASS_HWMON,
6539df7305bSSteve Glendinning .driver = {
6549df7305bSSteve Glendinning .name = "emc2103",
6559df7305bSSteve Glendinning },
6561975d167SUwe Kleine-König .probe = emc2103_probe,
6579df7305bSSteve Glendinning .id_table = emc2103_ids,
6589df7305bSSteve Glendinning .detect = emc2103_detect,
6599df7305bSSteve Glendinning .address_list = normal_i2c,
6609df7305bSSteve Glendinning };
6619df7305bSSteve Glendinning
662f0967eeaSAxel Lin module_i2c_driver(emc2103_driver);
6639df7305bSSteve Glendinning
66490b24cfbSSteve Glendinning MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
6659df7305bSSteve Glendinning MODULE_DESCRIPTION("SMSC EMC2103 hwmon driver");
6669df7305bSSteve Glendinning MODULE_LICENSE("GPL");
667