xref: /linux/drivers/hwmon/emc2103.c (revision 94bf70da8ac3f815411a24a6ca42e7327c4a4bbb)
19df7305bSSteve Glendinning /*
2bf0f3a04SGuenter Roeck  * emc2103.c - Support for SMSC EMC2103
3bf0f3a04SGuenter Roeck  * Copyright (c) 2010 SMSC
4bf0f3a04SGuenter Roeck  *
5bf0f3a04SGuenter Roeck  * This program is free software; you can redistribute it and/or modify
6bf0f3a04SGuenter Roeck  * it under the terms of the GNU General Public License as published by
7bf0f3a04SGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
8bf0f3a04SGuenter Roeck  * (at your option) any later version.
9bf0f3a04SGuenter Roeck  *
10bf0f3a04SGuenter Roeck  * This program is distributed in the hope that it will be useful,
11bf0f3a04SGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12bf0f3a04SGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13bf0f3a04SGuenter Roeck  * GNU General Public License for more details.
14bf0f3a04SGuenter Roeck  *
15bf0f3a04SGuenter Roeck  * You should have received a copy of the GNU General Public License
16bf0f3a04SGuenter Roeck  * along with this program; if not, write to the Free Software
17bf0f3a04SGuenter Roeck  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
189df7305bSSteve Glendinning  */
199df7305bSSteve Glendinning 
209df7305bSSteve Glendinning #include <linux/module.h>
219df7305bSSteve Glendinning #include <linux/init.h>
229df7305bSSteve Glendinning #include <linux/slab.h>
239df7305bSSteve Glendinning #include <linux/jiffies.h>
249df7305bSSteve Glendinning #include <linux/i2c.h>
259df7305bSSteve Glendinning #include <linux/hwmon.h>
269df7305bSSteve Glendinning #include <linux/hwmon-sysfs.h>
279df7305bSSteve Glendinning #include <linux/err.h>
289df7305bSSteve Glendinning #include <linux/mutex.h>
299df7305bSSteve Glendinning 
309df7305bSSteve Glendinning /* Addresses scanned */
319df7305bSSteve Glendinning static const unsigned short normal_i2c[] = { 0x2E, I2C_CLIENT_END };
329df7305bSSteve Glendinning 
339df7305bSSteve Glendinning static const u8 REG_TEMP[4] = { 0x00, 0x02, 0x04, 0x06 };
349df7305bSSteve Glendinning static const u8 REG_TEMP_MIN[4] = { 0x3c, 0x38, 0x39, 0x3a };
359df7305bSSteve Glendinning static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 };
369df7305bSSteve Glendinning 
379df7305bSSteve Glendinning #define REG_CONF1		0x20
389df7305bSSteve Glendinning #define REG_TEMP_MAX_ALARM	0x24
399df7305bSSteve Glendinning #define REG_TEMP_MIN_ALARM	0x25
409df7305bSSteve Glendinning #define REG_FAN_CONF1		0x42
419df7305bSSteve Glendinning #define REG_FAN_TARGET_LO	0x4c
429df7305bSSteve Glendinning #define REG_FAN_TARGET_HI	0x4d
439df7305bSSteve Glendinning #define REG_FAN_TACH_HI		0x4e
449df7305bSSteve Glendinning #define REG_FAN_TACH_LO		0x4f
459df7305bSSteve Glendinning #define REG_PRODUCT_ID		0xfd
469df7305bSSteve Glendinning #define REG_MFG_ID		0xfe
479df7305bSSteve Glendinning 
489df7305bSSteve Glendinning /* equation 4 from datasheet: rpm = (3932160 * multipler) / count */
499df7305bSSteve Glendinning #define FAN_RPM_FACTOR		3932160
509df7305bSSteve Glendinning 
51bf0f3a04SGuenter Roeck /*
52bf0f3a04SGuenter Roeck  * 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes
539df7305bSSteve Glendinning  * in anti-parallel mode, and in this configuration both can be read
549df7305bSSteve Glendinning  * independently (so we have 4 temperature inputs).  The device can't
559df7305bSSteve Glendinning  * detect if it's connected in this mode, so we have to manually enable
569df7305bSSteve Glendinning  * it.  Default is to leave the device in the state it's already in (-1).
57bf0f3a04SGuenter Roeck  * This parameter allows APD mode to be optionally forced on or off
58bf0f3a04SGuenter Roeck  */
599df7305bSSteve Glendinning static int apd = -1;
6069116f27SRusty Russell module_param(apd, bint, 0);
6154f0ffc4SDan Carpenter MODULE_PARM_DESC(apd, "Set to zero to disable anti-parallel diode mode");
629df7305bSSteve Glendinning 
639df7305bSSteve Glendinning struct temperature {
649df7305bSSteve Glendinning 	s8	degrees;
659df7305bSSteve Glendinning 	u8	fraction;	/* 0-7 multiples of 0.125 */
669df7305bSSteve Glendinning };
679df7305bSSteve Glendinning 
689df7305bSSteve Glendinning struct emc2103_data {
699dd304f8SAxel Lin 	struct i2c_client	*client;
709dd304f8SAxel Lin 	const struct		attribute_group *groups[4];
719df7305bSSteve Glendinning 	struct mutex		update_lock;
729df7305bSSteve Glendinning 	bool			valid;		/* registers are valid */
739df7305bSSteve Glendinning 	bool			fan_rpm_control;
749df7305bSSteve Glendinning 	int			temp_count;	/* num of temp sensors */
759df7305bSSteve Glendinning 	unsigned long		last_updated;	/* in jiffies */
769df7305bSSteve Glendinning 	struct temperature	temp[4];	/* internal + 3 external */
779df7305bSSteve Glendinning 	s8			temp_min[4];	/* no fractional part */
789df7305bSSteve Glendinning 	s8			temp_max[4];    /* no fractional part */
799df7305bSSteve Glendinning 	u8			temp_min_alarm;
809df7305bSSteve Glendinning 	u8			temp_max_alarm;
819df7305bSSteve Glendinning 	u8			fan_multiplier;
829df7305bSSteve Glendinning 	u16			fan_tach;
839df7305bSSteve Glendinning 	u16			fan_target;
849df7305bSSteve Glendinning };
859df7305bSSteve Glendinning 
869df7305bSSteve Glendinning static int read_u8_from_i2c(struct i2c_client *client, u8 i2c_reg, u8 *output)
879df7305bSSteve Glendinning {
889df7305bSSteve Glendinning 	int status = i2c_smbus_read_byte_data(client, i2c_reg);
899df7305bSSteve Glendinning 	if (status < 0) {
909df7305bSSteve Glendinning 		dev_warn(&client->dev, "reg 0x%02x, err %d\n",
919df7305bSSteve Glendinning 			i2c_reg, status);
929df7305bSSteve Glendinning 	} else {
939df7305bSSteve Glendinning 		*output = status;
949df7305bSSteve Glendinning 	}
959df7305bSSteve Glendinning 	return status;
969df7305bSSteve Glendinning }
979df7305bSSteve Glendinning 
989df7305bSSteve Glendinning static void read_temp_from_i2c(struct i2c_client *client, u8 i2c_reg,
999df7305bSSteve Glendinning 			       struct temperature *temp)
1009df7305bSSteve Glendinning {
1019df7305bSSteve Glendinning 	u8 degrees, fractional;
1029df7305bSSteve Glendinning 
1039df7305bSSteve Glendinning 	if (read_u8_from_i2c(client, i2c_reg, &degrees) < 0)
1049df7305bSSteve Glendinning 		return;
1059df7305bSSteve Glendinning 
1069df7305bSSteve Glendinning 	if (read_u8_from_i2c(client, i2c_reg + 1, &fractional) < 0)
1079df7305bSSteve Glendinning 		return;
1089df7305bSSteve Glendinning 
1099df7305bSSteve Glendinning 	temp->degrees = degrees;
1109df7305bSSteve Glendinning 	temp->fraction = (fractional & 0xe0) >> 5;
1119df7305bSSteve Glendinning }
1129df7305bSSteve Glendinning 
1139df7305bSSteve Glendinning static void read_fan_from_i2c(struct i2c_client *client, u16 *output,
1149df7305bSSteve Glendinning 			      u8 hi_addr, u8 lo_addr)
1159df7305bSSteve Glendinning {
1169df7305bSSteve Glendinning 	u8 high_byte, lo_byte;
1179df7305bSSteve Glendinning 
1189df7305bSSteve Glendinning 	if (read_u8_from_i2c(client, hi_addr, &high_byte) < 0)
1199df7305bSSteve Glendinning 		return;
1209df7305bSSteve Glendinning 
1219df7305bSSteve Glendinning 	if (read_u8_from_i2c(client, lo_addr, &lo_byte) < 0)
1229df7305bSSteve Glendinning 		return;
1239df7305bSSteve Glendinning 
1249df7305bSSteve Glendinning 	*output = ((u16)high_byte << 5) | (lo_byte >> 3);
1259df7305bSSteve Glendinning }
1269df7305bSSteve Glendinning 
1279df7305bSSteve Glendinning static void write_fan_target_to_i2c(struct i2c_client *client, u16 new_target)
1289df7305bSSteve Glendinning {
1299df7305bSSteve Glendinning 	u8 high_byte = (new_target & 0x1fe0) >> 5;
1309df7305bSSteve Glendinning 	u8 low_byte = (new_target & 0x001f) << 3;
1319df7305bSSteve Glendinning 	i2c_smbus_write_byte_data(client, REG_FAN_TARGET_LO, low_byte);
1329df7305bSSteve Glendinning 	i2c_smbus_write_byte_data(client, REG_FAN_TARGET_HI, high_byte);
1339df7305bSSteve Glendinning }
1349df7305bSSteve Glendinning 
1359df7305bSSteve Glendinning static void read_fan_config_from_i2c(struct i2c_client *client)
1369df7305bSSteve Glendinning 
1379df7305bSSteve Glendinning {
1389df7305bSSteve Glendinning 	struct emc2103_data *data = i2c_get_clientdata(client);
1399df7305bSSteve Glendinning 	u8 conf1;
1409df7305bSSteve Glendinning 
1419df7305bSSteve Glendinning 	if (read_u8_from_i2c(client, REG_FAN_CONF1, &conf1) < 0)
1429df7305bSSteve Glendinning 		return;
1439df7305bSSteve Glendinning 
1449df7305bSSteve Glendinning 	data->fan_multiplier = 1 << ((conf1 & 0x60) >> 5);
1459df7305bSSteve Glendinning 	data->fan_rpm_control = (conf1 & 0x80) != 0;
1469df7305bSSteve Glendinning }
1479df7305bSSteve Glendinning 
1489df7305bSSteve Glendinning static struct emc2103_data *emc2103_update_device(struct device *dev)
1499df7305bSSteve Glendinning {
1509dd304f8SAxel Lin 	struct emc2103_data *data = dev_get_drvdata(dev);
1519dd304f8SAxel Lin 	struct i2c_client *client = data->client;
1529df7305bSSteve Glendinning 
1539df7305bSSteve Glendinning 	mutex_lock(&data->update_lock);
1549df7305bSSteve Glendinning 
1559df7305bSSteve Glendinning 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
1569df7305bSSteve Glendinning 	    || !data->valid) {
1579df7305bSSteve Glendinning 		int i;
1589df7305bSSteve Glendinning 
1599df7305bSSteve Glendinning 		for (i = 0; i < data->temp_count; i++) {
1609df7305bSSteve Glendinning 			read_temp_from_i2c(client, REG_TEMP[i], &data->temp[i]);
1619df7305bSSteve Glendinning 			read_u8_from_i2c(client, REG_TEMP_MIN[i],
1629df7305bSSteve Glendinning 				&data->temp_min[i]);
1639df7305bSSteve Glendinning 			read_u8_from_i2c(client, REG_TEMP_MAX[i],
1649df7305bSSteve Glendinning 				&data->temp_max[i]);
1659df7305bSSteve Glendinning 		}
1669df7305bSSteve Glendinning 
1679df7305bSSteve Glendinning 		read_u8_from_i2c(client, REG_TEMP_MIN_ALARM,
1689df7305bSSteve Glendinning 			&data->temp_min_alarm);
1699df7305bSSteve Glendinning 		read_u8_from_i2c(client, REG_TEMP_MAX_ALARM,
1709df7305bSSteve Glendinning 			&data->temp_max_alarm);
1719df7305bSSteve Glendinning 
1729df7305bSSteve Glendinning 		read_fan_from_i2c(client, &data->fan_tach,
1739df7305bSSteve Glendinning 			REG_FAN_TACH_HI, REG_FAN_TACH_LO);
1749df7305bSSteve Glendinning 		read_fan_from_i2c(client, &data->fan_target,
1759df7305bSSteve Glendinning 			REG_FAN_TARGET_HI, REG_FAN_TARGET_LO);
1769df7305bSSteve Glendinning 		read_fan_config_from_i2c(client);
1779df7305bSSteve Glendinning 
1789df7305bSSteve Glendinning 		data->last_updated = jiffies;
1799df7305bSSteve Glendinning 		data->valid = true;
1809df7305bSSteve Glendinning 	}
1819df7305bSSteve Glendinning 
1829df7305bSSteve Glendinning 	mutex_unlock(&data->update_lock);
1839df7305bSSteve Glendinning 
1849df7305bSSteve Glendinning 	return data;
1859df7305bSSteve Glendinning }
1869df7305bSSteve Glendinning 
1879df7305bSSteve Glendinning static ssize_t
188*94bf70daSGuenter Roeck temp_show(struct device *dev, struct device_attribute *da, char *buf)
1899df7305bSSteve Glendinning {
1909df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
1919df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
1929df7305bSSteve Glendinning 	int millidegrees = data->temp[nr].degrees * 1000
1939df7305bSSteve Glendinning 		+ data->temp[nr].fraction * 125;
1949df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", millidegrees);
1959df7305bSSteve Glendinning }
1969df7305bSSteve Glendinning 
1979df7305bSSteve Glendinning static ssize_t
198*94bf70daSGuenter Roeck temp_min_show(struct device *dev, struct device_attribute *da, char *buf)
1999df7305bSSteve Glendinning {
2009df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2019df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
2029df7305bSSteve Glendinning 	int millidegrees = data->temp_min[nr] * 1000;
2039df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", millidegrees);
2049df7305bSSteve Glendinning }
2059df7305bSSteve Glendinning 
2069df7305bSSteve Glendinning static ssize_t
207*94bf70daSGuenter Roeck temp_max_show(struct device *dev, struct device_attribute *da, char *buf)
2089df7305bSSteve Glendinning {
2099df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2109df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
2119df7305bSSteve Glendinning 	int millidegrees = data->temp_max[nr] * 1000;
2129df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", millidegrees);
2139df7305bSSteve Glendinning }
2149df7305bSSteve Glendinning 
2159df7305bSSteve Glendinning static ssize_t
216*94bf70daSGuenter Roeck temp_fault_show(struct device *dev, struct device_attribute *da, char *buf)
2179df7305bSSteve Glendinning {
2189df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2199df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
2209df7305bSSteve Glendinning 	bool fault = (data->temp[nr].degrees == -128);
2219df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", fault ? 1 : 0);
2229df7305bSSteve Glendinning }
2239df7305bSSteve Glendinning 
2249df7305bSSteve Glendinning static ssize_t
225*94bf70daSGuenter Roeck temp_min_alarm_show(struct device *dev, struct device_attribute *da,
226*94bf70daSGuenter Roeck 		    char *buf)
2279df7305bSSteve Glendinning {
2289df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2299df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
2309df7305bSSteve Glendinning 	bool alarm = data->temp_min_alarm & (1 << nr);
2319df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", alarm ? 1 : 0);
2329df7305bSSteve Glendinning }
2339df7305bSSteve Glendinning 
2349df7305bSSteve Glendinning static ssize_t
235*94bf70daSGuenter Roeck temp_max_alarm_show(struct device *dev, struct device_attribute *da,
236*94bf70daSGuenter Roeck 		    char *buf)
2379df7305bSSteve Glendinning {
2389df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2399df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
2409df7305bSSteve Glendinning 	bool alarm = data->temp_max_alarm & (1 << nr);
2419df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", alarm ? 1 : 0);
2429df7305bSSteve Glendinning }
2439df7305bSSteve Glendinning 
244*94bf70daSGuenter Roeck static ssize_t temp_min_store(struct device *dev, struct device_attribute *da,
2459df7305bSSteve Glendinning 			      const char *buf, size_t count)
2469df7305bSSteve Glendinning {
2479df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2489dd304f8SAxel Lin 	struct emc2103_data *data = dev_get_drvdata(dev);
2499dd304f8SAxel Lin 	struct i2c_client *client = data->client;
2509df7305bSSteve Glendinning 	long val;
2519df7305bSSteve Glendinning 
252179c4fdbSFrans Meulenbroeks 	int result = kstrtol(buf, 10, &val);
2539df7305bSSteve Glendinning 	if (result < 0)
2541a3abbd0SSachin Kamat 		return result;
2559df7305bSSteve Glendinning 
256ca1b10b8SGuenter Roeck 	val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000);
2579df7305bSSteve Glendinning 
2589df7305bSSteve Glendinning 	mutex_lock(&data->update_lock);
2599df7305bSSteve Glendinning 	data->temp_min[nr] = val;
2609df7305bSSteve Glendinning 	i2c_smbus_write_byte_data(client, REG_TEMP_MIN[nr], val);
2619df7305bSSteve Glendinning 	mutex_unlock(&data->update_lock);
2629df7305bSSteve Glendinning 
2639df7305bSSteve Glendinning 	return count;
2649df7305bSSteve Glendinning }
2659df7305bSSteve Glendinning 
266*94bf70daSGuenter Roeck static ssize_t temp_max_store(struct device *dev, struct device_attribute *da,
2679df7305bSSteve Glendinning 			      const char *buf, size_t count)
2689df7305bSSteve Glendinning {
2699df7305bSSteve Glendinning 	int nr = to_sensor_dev_attr(da)->index;
2709dd304f8SAxel Lin 	struct emc2103_data *data = dev_get_drvdata(dev);
2719dd304f8SAxel Lin 	struct i2c_client *client = data->client;
2729df7305bSSteve Glendinning 	long val;
2739df7305bSSteve Glendinning 
274179c4fdbSFrans Meulenbroeks 	int result = kstrtol(buf, 10, &val);
2759df7305bSSteve Glendinning 	if (result < 0)
2761a3abbd0SSachin Kamat 		return result;
2779df7305bSSteve Glendinning 
278ca1b10b8SGuenter Roeck 	val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000);
2799df7305bSSteve Glendinning 
2809df7305bSSteve Glendinning 	mutex_lock(&data->update_lock);
2819df7305bSSteve Glendinning 	data->temp_max[nr] = val;
2829df7305bSSteve Glendinning 	i2c_smbus_write_byte_data(client, REG_TEMP_MAX[nr], val);
2839df7305bSSteve Glendinning 	mutex_unlock(&data->update_lock);
2849df7305bSSteve Glendinning 
2859df7305bSSteve Glendinning 	return count;
2869df7305bSSteve Glendinning }
2879df7305bSSteve Glendinning 
2889df7305bSSteve Glendinning static ssize_t
2894cd0183dSJulia Lawall fan1_input_show(struct device *dev, struct device_attribute *da, char *buf)
2909df7305bSSteve Glendinning {
2919df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
2929df7305bSSteve Glendinning 	int rpm = 0;
2939df7305bSSteve Glendinning 	if (data->fan_tach != 0)
2949df7305bSSteve Glendinning 		rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach;
2959df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", rpm);
2969df7305bSSteve Glendinning }
2979df7305bSSteve Glendinning 
2989df7305bSSteve Glendinning static ssize_t
2994cd0183dSJulia Lawall fan1_div_show(struct device *dev, struct device_attribute *da, char *buf)
3009df7305bSSteve Glendinning {
3019df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
3029df7305bSSteve Glendinning 	int fan_div = 8 / data->fan_multiplier;
3039df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", fan_div);
3049df7305bSSteve Glendinning }
3059df7305bSSteve Glendinning 
306bf0f3a04SGuenter Roeck /*
307bf0f3a04SGuenter Roeck  * Note: we also update the fan target here, because its value is
308bf0f3a04SGuenter Roeck  * determined in part by the fan clock divider.  This follows the principle
309bf0f3a04SGuenter Roeck  * of least surprise; the user doesn't expect the fan target to change just
310bf0f3a04SGuenter Roeck  * because the divider changed.
311bf0f3a04SGuenter Roeck  */
3124cd0183dSJulia Lawall static ssize_t fan1_div_store(struct device *dev, struct device_attribute *da,
3139df7305bSSteve Glendinning 			      const char *buf, size_t count)
3149df7305bSSteve Glendinning {
3159df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
3169dd304f8SAxel Lin 	struct i2c_client *client = data->client;
3179df7305bSSteve Glendinning 	int new_range_bits, old_div = 8 / data->fan_multiplier;
3189df7305bSSteve Glendinning 	long new_div;
3199df7305bSSteve Glendinning 
320179c4fdbSFrans Meulenbroeks 	int status = kstrtol(buf, 10, &new_div);
3219df7305bSSteve Glendinning 	if (status < 0)
3221a3abbd0SSachin Kamat 		return status;
3239df7305bSSteve Glendinning 
3249df7305bSSteve Glendinning 	if (new_div == old_div) /* No change */
3259df7305bSSteve Glendinning 		return count;
3269df7305bSSteve Glendinning 
3279df7305bSSteve Glendinning 	switch (new_div) {
3289df7305bSSteve Glendinning 	case 1:
3299df7305bSSteve Glendinning 		new_range_bits = 3;
3309df7305bSSteve Glendinning 		break;
3319df7305bSSteve Glendinning 	case 2:
3329df7305bSSteve Glendinning 		new_range_bits = 2;
3339df7305bSSteve Glendinning 		break;
3349df7305bSSteve Glendinning 	case 4:
3359df7305bSSteve Glendinning 		new_range_bits = 1;
3369df7305bSSteve Glendinning 		break;
3379df7305bSSteve Glendinning 	case 8:
3389df7305bSSteve Glendinning 		new_range_bits = 0;
3399df7305bSSteve Glendinning 		break;
3409df7305bSSteve Glendinning 	default:
3419df7305bSSteve Glendinning 		return -EINVAL;
3429df7305bSSteve Glendinning 	}
3439df7305bSSteve Glendinning 
3449df7305bSSteve Glendinning 	mutex_lock(&data->update_lock);
3459df7305bSSteve Glendinning 
3469df7305bSSteve Glendinning 	status = i2c_smbus_read_byte_data(client, REG_FAN_CONF1);
3479df7305bSSteve Glendinning 	if (status < 0) {
3489df7305bSSteve Glendinning 		dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
3499df7305bSSteve Glendinning 			REG_FAN_CONF1, status);
3509df7305bSSteve Glendinning 		mutex_unlock(&data->update_lock);
3519bf3babfSGuenter Roeck 		return status;
3529df7305bSSteve Glendinning 	}
3539df7305bSSteve Glendinning 	status &= 0x9F;
3549df7305bSSteve Glendinning 	status |= (new_range_bits << 5);
3559df7305bSSteve Glendinning 	i2c_smbus_write_byte_data(client, REG_FAN_CONF1, status);
3569df7305bSSteve Glendinning 
3579df7305bSSteve Glendinning 	data->fan_multiplier = 8 / new_div;
3589df7305bSSteve Glendinning 
3599df7305bSSteve Glendinning 	/* update fan target if high byte is not disabled */
3609df7305bSSteve Glendinning 	if ((data->fan_target & 0x1fe0) != 0x1fe0) {
3619df7305bSSteve Glendinning 		u16 new_target = (data->fan_target * old_div) / new_div;
3629df7305bSSteve Glendinning 		data->fan_target = min(new_target, (u16)0x1fff);
3639df7305bSSteve Glendinning 		write_fan_target_to_i2c(client, data->fan_target);
3649df7305bSSteve Glendinning 	}
3659df7305bSSteve Glendinning 
3669df7305bSSteve Glendinning 	/* invalidate data to force re-read from hardware */
3679df7305bSSteve Glendinning 	data->valid = false;
3689df7305bSSteve Glendinning 
3699df7305bSSteve Glendinning 	mutex_unlock(&data->update_lock);
3709df7305bSSteve Glendinning 	return count;
3719df7305bSSteve Glendinning }
3729df7305bSSteve Glendinning 
3739df7305bSSteve Glendinning static ssize_t
3744cd0183dSJulia Lawall fan1_target_show(struct device *dev, struct device_attribute *da, char *buf)
3759df7305bSSteve Glendinning {
3769df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
3779df7305bSSteve Glendinning 	int rpm = 0;
3789df7305bSSteve Glendinning 
3799df7305bSSteve Glendinning 	/* high byte of 0xff indicates disabled so return 0 */
3809df7305bSSteve Glendinning 	if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0))
3819df7305bSSteve Glendinning 		rpm = (FAN_RPM_FACTOR * data->fan_multiplier)
3829df7305bSSteve Glendinning 			/ data->fan_target;
3839df7305bSSteve Glendinning 
3849df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", rpm);
3859df7305bSSteve Glendinning }
3869df7305bSSteve Glendinning 
3874cd0183dSJulia Lawall static ssize_t fan1_target_store(struct device *dev,
3884cd0183dSJulia Lawall 				 struct device_attribute *da, const char *buf,
3894cd0183dSJulia Lawall 				 size_t count)
3909df7305bSSteve Glendinning {
3919df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
3929dd304f8SAxel Lin 	struct i2c_client *client = data->client;
393f6c2dd20SGuenter Roeck 	unsigned long rpm_target;
3949df7305bSSteve Glendinning 
395f6c2dd20SGuenter Roeck 	int result = kstrtoul(buf, 10, &rpm_target);
3969df7305bSSteve Glendinning 	if (result < 0)
3971a3abbd0SSachin Kamat 		return result;
3989df7305bSSteve Glendinning 
3999df7305bSSteve Glendinning 	/* Datasheet states 16384 as maximum RPM target (table 3.2) */
400f6c2dd20SGuenter Roeck 	rpm_target = clamp_val(rpm_target, 0, 16384);
4019df7305bSSteve Glendinning 
4029df7305bSSteve Glendinning 	mutex_lock(&data->update_lock);
4039df7305bSSteve Glendinning 
4049df7305bSSteve Glendinning 	if (rpm_target == 0)
4059df7305bSSteve Glendinning 		data->fan_target = 0x1fff;
4069df7305bSSteve Glendinning 	else
4072a844c14SGuenter Roeck 		data->fan_target = clamp_val(
4089df7305bSSteve Glendinning 			(FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target,
4099df7305bSSteve Glendinning 			0, 0x1fff);
4109df7305bSSteve Glendinning 
4119df7305bSSteve Glendinning 	write_fan_target_to_i2c(client, data->fan_target);
4129df7305bSSteve Glendinning 
4139df7305bSSteve Glendinning 	mutex_unlock(&data->update_lock);
4149df7305bSSteve Glendinning 	return count;
4159df7305bSSteve Glendinning }
4169df7305bSSteve Glendinning 
4179df7305bSSteve Glendinning static ssize_t
4184cd0183dSJulia Lawall fan1_fault_show(struct device *dev, struct device_attribute *da, char *buf)
4199df7305bSSteve Glendinning {
4209df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
4219df7305bSSteve Glendinning 	bool fault = ((data->fan_tach & 0x1fe0) == 0x1fe0);
4229df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", fault ? 1 : 0);
4239df7305bSSteve Glendinning }
4249df7305bSSteve Glendinning 
4259df7305bSSteve Glendinning static ssize_t
4264cd0183dSJulia Lawall pwm1_enable_show(struct device *dev, struct device_attribute *da, char *buf)
4279df7305bSSteve Glendinning {
4289df7305bSSteve Glendinning 	struct emc2103_data *data = emc2103_update_device(dev);
4299df7305bSSteve Glendinning 	return sprintf(buf, "%d\n", data->fan_rpm_control ? 3 : 0);
4309df7305bSSteve Glendinning }
4319df7305bSSteve Glendinning 
4324cd0183dSJulia Lawall static ssize_t pwm1_enable_store(struct device *dev,
4334cd0183dSJulia Lawall 				 struct device_attribute *da, const char *buf,
4344cd0183dSJulia Lawall 				 size_t count)
4359df7305bSSteve Glendinning {
4369dd304f8SAxel Lin 	struct emc2103_data *data = dev_get_drvdata(dev);
4379dd304f8SAxel Lin 	struct i2c_client *client = data->client;
4389df7305bSSteve Glendinning 	long new_value;
4399df7305bSSteve Glendinning 	u8 conf_reg;
4409df7305bSSteve Glendinning 
441179c4fdbSFrans Meulenbroeks 	int result = kstrtol(buf, 10, &new_value);
4429df7305bSSteve Glendinning 	if (result < 0)
4431a3abbd0SSachin Kamat 		return result;
4449df7305bSSteve Glendinning 
4459df7305bSSteve Glendinning 	mutex_lock(&data->update_lock);
4469df7305bSSteve Glendinning 	switch (new_value) {
4479df7305bSSteve Glendinning 	case 0:
4489df7305bSSteve Glendinning 		data->fan_rpm_control = false;
4499df7305bSSteve Glendinning 		break;
4509df7305bSSteve Glendinning 	case 3:
4519df7305bSSteve Glendinning 		data->fan_rpm_control = true;
4529df7305bSSteve Glendinning 		break;
4539df7305bSSteve Glendinning 	default:
4542355375eSGuenter Roeck 		count = -EINVAL;
4552355375eSGuenter Roeck 		goto err;
4569df7305bSSteve Glendinning 	}
4579df7305bSSteve Glendinning 
4582355375eSGuenter Roeck 	result = read_u8_from_i2c(client, REG_FAN_CONF1, &conf_reg);
4592355375eSGuenter Roeck 	if (result) {
4602355375eSGuenter Roeck 		count = result;
4612355375eSGuenter Roeck 		goto err;
4622355375eSGuenter Roeck 	}
4639df7305bSSteve Glendinning 
4649df7305bSSteve Glendinning 	if (data->fan_rpm_control)
4659df7305bSSteve Glendinning 		conf_reg |= 0x80;
4669df7305bSSteve Glendinning 	else
4679df7305bSSteve Glendinning 		conf_reg &= ~0x80;
4689df7305bSSteve Glendinning 
4699df7305bSSteve Glendinning 	i2c_smbus_write_byte_data(client, REG_FAN_CONF1, conf_reg);
4702355375eSGuenter Roeck err:
4719df7305bSSteve Glendinning 	mutex_unlock(&data->update_lock);
4729df7305bSSteve Glendinning 	return count;
4739df7305bSSteve Glendinning }
4749df7305bSSteve Glendinning 
475*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
476*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
477*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
478*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
479*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, temp_min_alarm, 0);
480*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, temp_max_alarm, 0);
4819df7305bSSteve Glendinning 
482*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
483*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
484*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
485*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
486*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, temp_min_alarm, 1);
487*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, temp_max_alarm, 1);
4889df7305bSSteve Glendinning 
489*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
490*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2);
491*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2);
492*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2);
493*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_min_alarm, temp_min_alarm, 2);
494*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, temp_max_alarm, 2);
4959df7305bSSteve Glendinning 
496*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3);
497*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp4_min, temp_min, 3);
498*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp4_max, temp_max, 3);
499*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3);
500*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_min_alarm, temp_min_alarm, 3);
501*94bf70daSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp4_max_alarm, temp_max_alarm, 3);
5029df7305bSSteve Glendinning 
5034cd0183dSJulia Lawall static DEVICE_ATTR_RO(fan1_input);
5044cd0183dSJulia Lawall static DEVICE_ATTR_RW(fan1_div);
5054cd0183dSJulia Lawall static DEVICE_ATTR_RW(fan1_target);
5064cd0183dSJulia Lawall static DEVICE_ATTR_RO(fan1_fault);
5079df7305bSSteve Glendinning 
5084cd0183dSJulia Lawall static DEVICE_ATTR_RW(pwm1_enable);
5099df7305bSSteve Glendinning 
5109df7305bSSteve Glendinning /* sensors present on all models */
5119df7305bSSteve Glendinning static struct attribute *emc2103_attributes[] = {
5129df7305bSSteve Glendinning 	&sensor_dev_attr_temp1_input.dev_attr.attr,
5139df7305bSSteve Glendinning 	&sensor_dev_attr_temp1_min.dev_attr.attr,
5149df7305bSSteve Glendinning 	&sensor_dev_attr_temp1_max.dev_attr.attr,
5159df7305bSSteve Glendinning 	&sensor_dev_attr_temp1_fault.dev_attr.attr,
5169df7305bSSteve Glendinning 	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
5179df7305bSSteve Glendinning 	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
5189df7305bSSteve Glendinning 	&sensor_dev_attr_temp2_input.dev_attr.attr,
5199df7305bSSteve Glendinning 	&sensor_dev_attr_temp2_min.dev_attr.attr,
5209df7305bSSteve Glendinning 	&sensor_dev_attr_temp2_max.dev_attr.attr,
5219df7305bSSteve Glendinning 	&sensor_dev_attr_temp2_fault.dev_attr.attr,
5229df7305bSSteve Glendinning 	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
5239df7305bSSteve Glendinning 	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
5249df7305bSSteve Glendinning 	&dev_attr_fan1_input.attr,
5259df7305bSSteve Glendinning 	&dev_attr_fan1_div.attr,
5269df7305bSSteve Glendinning 	&dev_attr_fan1_target.attr,
5279df7305bSSteve Glendinning 	&dev_attr_fan1_fault.attr,
5289df7305bSSteve Glendinning 	&dev_attr_pwm1_enable.attr,
5299df7305bSSteve Glendinning 	NULL
5309df7305bSSteve Glendinning };
5319df7305bSSteve Glendinning 
5329df7305bSSteve Glendinning /* extra temperature sensors only present on 2103-2 and 2103-4 */
5339df7305bSSteve Glendinning static struct attribute *emc2103_attributes_temp3[] = {
5349df7305bSSteve Glendinning 	&sensor_dev_attr_temp3_input.dev_attr.attr,
5359df7305bSSteve Glendinning 	&sensor_dev_attr_temp3_min.dev_attr.attr,
5369df7305bSSteve Glendinning 	&sensor_dev_attr_temp3_max.dev_attr.attr,
5379df7305bSSteve Glendinning 	&sensor_dev_attr_temp3_fault.dev_attr.attr,
5389df7305bSSteve Glendinning 	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
5399df7305bSSteve Glendinning 	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
5409df7305bSSteve Glendinning 	NULL
5419df7305bSSteve Glendinning };
5429df7305bSSteve Glendinning 
5439df7305bSSteve Glendinning /* extra temperature sensors only present on 2103-2 and 2103-4 in APD mode */
5449df7305bSSteve Glendinning static struct attribute *emc2103_attributes_temp4[] = {
5459df7305bSSteve Glendinning 	&sensor_dev_attr_temp4_input.dev_attr.attr,
5469df7305bSSteve Glendinning 	&sensor_dev_attr_temp4_min.dev_attr.attr,
5479df7305bSSteve Glendinning 	&sensor_dev_attr_temp4_max.dev_attr.attr,
5489df7305bSSteve Glendinning 	&sensor_dev_attr_temp4_fault.dev_attr.attr,
5499df7305bSSteve Glendinning 	&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
5509df7305bSSteve Glendinning 	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
5519df7305bSSteve Glendinning 	NULL
5529df7305bSSteve Glendinning };
5539df7305bSSteve Glendinning 
5549df7305bSSteve Glendinning static const struct attribute_group emc2103_group = {
5559df7305bSSteve Glendinning 	.attrs = emc2103_attributes,
5569df7305bSSteve Glendinning };
5579df7305bSSteve Glendinning 
5589df7305bSSteve Glendinning static const struct attribute_group emc2103_temp3_group = {
5599df7305bSSteve Glendinning 	.attrs = emc2103_attributes_temp3,
5609df7305bSSteve Glendinning };
5619df7305bSSteve Glendinning 
5629df7305bSSteve Glendinning static const struct attribute_group emc2103_temp4_group = {
5639df7305bSSteve Glendinning 	.attrs = emc2103_attributes_temp4,
5649df7305bSSteve Glendinning };
5659df7305bSSteve Glendinning 
5669df7305bSSteve Glendinning static int
5679df7305bSSteve Glendinning emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
5689df7305bSSteve Glendinning {
5699df7305bSSteve Glendinning 	struct emc2103_data *data;
5709dd304f8SAxel Lin 	struct device *hwmon_dev;
5719dd304f8SAxel Lin 	int status, idx = 0;
5729df7305bSSteve Glendinning 
5739df7305bSSteve Glendinning 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
5749df7305bSSteve Glendinning 		return -EIO;
5759df7305bSSteve Glendinning 
57659da32d8SGuenter Roeck 	data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
57759da32d8SGuenter Roeck 			    GFP_KERNEL);
5789df7305bSSteve Glendinning 	if (!data)
5799df7305bSSteve Glendinning 		return -ENOMEM;
5809df7305bSSteve Glendinning 
5819df7305bSSteve Glendinning 	i2c_set_clientdata(client, data);
5829dd304f8SAxel Lin 	data->client = client;
5839df7305bSSteve Glendinning 	mutex_init(&data->update_lock);
5849df7305bSSteve Glendinning 
5859df7305bSSteve Glendinning 	/* 2103-2 and 2103-4 have 3 external diodes, 2103-1 has 1 */
5869df7305bSSteve Glendinning 	status = i2c_smbus_read_byte_data(client, REG_PRODUCT_ID);
5879df7305bSSteve Glendinning 	if (status == 0x24) {
5889df7305bSSteve Glendinning 		/* 2103-1 only has 1 external diode */
5899df7305bSSteve Glendinning 		data->temp_count = 2;
5909df7305bSSteve Glendinning 	} else {
5919df7305bSSteve Glendinning 		/* 2103-2 and 2103-4 have 3 or 4 external diodes */
5929df7305bSSteve Glendinning 		status = i2c_smbus_read_byte_data(client, REG_CONF1);
5939df7305bSSteve Glendinning 		if (status < 0) {
5949df7305bSSteve Glendinning 			dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
5959df7305bSSteve Glendinning 				status);
59659da32d8SGuenter Roeck 			return status;
5979df7305bSSteve Glendinning 		}
5989df7305bSSteve Glendinning 
5999df7305bSSteve Glendinning 		/* detect current state of hardware */
6009df7305bSSteve Glendinning 		data->temp_count = (status & 0x01) ? 4 : 3;
6019df7305bSSteve Glendinning 
6029df7305bSSteve Glendinning 		/* force APD state if module parameter is set */
6039df7305bSSteve Glendinning 		if (apd == 0) {
6049df7305bSSteve Glendinning 			/* force APD mode off */
6059df7305bSSteve Glendinning 			data->temp_count = 3;
6069df7305bSSteve Glendinning 			status &= ~(0x01);
6079df7305bSSteve Glendinning 			i2c_smbus_write_byte_data(client, REG_CONF1, status);
6089df7305bSSteve Glendinning 		} else if (apd == 1) {
6099df7305bSSteve Glendinning 			/* force APD mode on */
6109df7305bSSteve Glendinning 			data->temp_count = 4;
6119df7305bSSteve Glendinning 			status |= 0x01;
6129df7305bSSteve Glendinning 			i2c_smbus_write_byte_data(client, REG_CONF1, status);
6139df7305bSSteve Glendinning 		}
6149df7305bSSteve Glendinning 	}
6159df7305bSSteve Glendinning 
6169dd304f8SAxel Lin 	/* sysfs hooks */
6179dd304f8SAxel Lin 	data->groups[idx++] = &emc2103_group;
6189dd304f8SAxel Lin 	if (data->temp_count >= 3)
6199dd304f8SAxel Lin 		data->groups[idx++] = &emc2103_temp3_group;
6209dd304f8SAxel Lin 	if (data->temp_count == 4)
6219dd304f8SAxel Lin 		data->groups[idx++] = &emc2103_temp4_group;
6229df7305bSSteve Glendinning 
6239dd304f8SAxel Lin 	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
6249dd304f8SAxel Lin 							   client->name, data,
6259dd304f8SAxel Lin 							   data->groups);
6269dd304f8SAxel Lin 	if (IS_ERR(hwmon_dev))
6279dd304f8SAxel Lin 		return PTR_ERR(hwmon_dev);
6289df7305bSSteve Glendinning 
6299df7305bSSteve Glendinning 	dev_info(&client->dev, "%s: sensor '%s'\n",
6309dd304f8SAxel Lin 		 dev_name(hwmon_dev), client->name);
6319df7305bSSteve Glendinning 
6329df7305bSSteve Glendinning 	return 0;
6339df7305bSSteve Glendinning }
6349df7305bSSteve Glendinning 
6359df7305bSSteve Glendinning static const struct i2c_device_id emc2103_ids[] = {
6369df7305bSSteve Glendinning 	{ "emc2103", 0, },
6379df7305bSSteve Glendinning 	{ /* LIST END */ }
6389df7305bSSteve Glendinning };
6399df7305bSSteve Glendinning MODULE_DEVICE_TABLE(i2c, emc2103_ids);
6409df7305bSSteve Glendinning 
6419df7305bSSteve Glendinning /* Return 0 if detection is successful, -ENODEV otherwise */
6429df7305bSSteve Glendinning static int
6439df7305bSSteve Glendinning emc2103_detect(struct i2c_client *new_client, struct i2c_board_info *info)
6449df7305bSSteve Glendinning {
6459df7305bSSteve Glendinning 	struct i2c_adapter *adapter = new_client->adapter;
6469df7305bSSteve Glendinning 	int manufacturer, product;
6479df7305bSSteve Glendinning 
6489df7305bSSteve Glendinning 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
6499df7305bSSteve Glendinning 		return -ENODEV;
6509df7305bSSteve Glendinning 
6519df7305bSSteve Glendinning 	manufacturer = i2c_smbus_read_byte_data(new_client, REG_MFG_ID);
6529df7305bSSteve Glendinning 	if (manufacturer != 0x5D)
6539df7305bSSteve Glendinning 		return -ENODEV;
6549df7305bSSteve Glendinning 
6559df7305bSSteve Glendinning 	product = i2c_smbus_read_byte_data(new_client, REG_PRODUCT_ID);
6569df7305bSSteve Glendinning 	if ((product != 0x24) && (product != 0x26))
6579df7305bSSteve Glendinning 		return -ENODEV;
6589df7305bSSteve Glendinning 
6599df7305bSSteve Glendinning 	strlcpy(info->type, "emc2103", I2C_NAME_SIZE);
6609df7305bSSteve Glendinning 
6619df7305bSSteve Glendinning 	return 0;
6629df7305bSSteve Glendinning }
6639df7305bSSteve Glendinning 
6649df7305bSSteve Glendinning static struct i2c_driver emc2103_driver = {
6659df7305bSSteve Glendinning 	.class		= I2C_CLASS_HWMON,
6669df7305bSSteve Glendinning 	.driver = {
6679df7305bSSteve Glendinning 		.name	= "emc2103",
6689df7305bSSteve Glendinning 	},
6699df7305bSSteve Glendinning 	.probe		= emc2103_probe,
6709df7305bSSteve Glendinning 	.id_table	= emc2103_ids,
6719df7305bSSteve Glendinning 	.detect		= emc2103_detect,
6729df7305bSSteve Glendinning 	.address_list	= normal_i2c,
6739df7305bSSteve Glendinning };
6749df7305bSSteve Glendinning 
675f0967eeaSAxel Lin module_i2c_driver(emc2103_driver);
6769df7305bSSteve Glendinning 
67790b24cfbSSteve Glendinning MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
6789df7305bSSteve Glendinning MODULE_DESCRIPTION("SMSC EMC2103 hwmon driver");
6799df7305bSSteve Glendinning MODULE_LICENSE("GPL");
680