xref: /linux/drivers/hwmon/emc2103.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
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, &degrees) < 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