diff options
Diffstat (limited to 'drivers/hwmon/pmbus')
| -rw-r--r-- | drivers/hwmon/pmbus/lm25066.c | 91 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/ltc2978.c | 37 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 92 | 
3 files changed, 151 insertions, 69 deletions
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 6a9d6edaacb..a26b1d1d951 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -1,5 +1,5 @@  /* - * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066 + * Hardware monitoring driver for LM25056 / LM25063 / LM25066 / LM5064 / LM5066   *   * Copyright (c) 2011 Ericsson AB.   * Copyright (c) 2013 Guenter Roeck @@ -27,7 +27,7 @@  #include <linux/i2c.h>  #include "pmbus.h" -enum chips { lm25056, lm25066, lm5064, lm5066 }; +enum chips { lm25056, lm25063, lm25066, lm5064, lm5066 };  #define LM25066_READ_VAUX		0xd0  #define LM25066_MFR_READ_IIN		0xd1 @@ -52,6 +52,11 @@ enum chips { lm25056, lm25066, lm5064, lm5066 };  #define LM25056_MFR_STS_VAUX_OV_WARN	(1 << 1)  #define LM25056_MFR_STS_VAUX_UV_WARN	(1 << 0) +/* LM25063 only */ + +#define LM25063_READ_VOUT_MAX		0xe5 +#define LM25063_READ_VOUT_MIN		0xe6 +  struct __coeff {  	short m, b, R;  }; @@ -59,7 +64,7 @@ struct __coeff {  #define PSC_CURRENT_IN_L	(PSC_NUM_CLASSES)  #define PSC_POWER_L		(PSC_NUM_CLASSES + 1) -static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = { +static struct __coeff lm25066_coeff[5][PSC_NUM_CLASSES + 2] = {  	[lm25056] = {  		[PSC_VOLTAGE_IN] = {  			.m = 16296, @@ -116,6 +121,36 @@ static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {  			.m = 16,  		},  	}, +	[lm25063] = { +		[PSC_VOLTAGE_IN] = { +			.m = 16000, +			.R = -2, +		}, +		[PSC_VOLTAGE_OUT] = { +			.m = 16000, +			.R = -2, +		}, +		[PSC_CURRENT_IN] = { +			.m = 10000, +			.R = -2, +		}, +		[PSC_CURRENT_IN_L] = { +			.m = 10000, +			.R = -2, +		}, +		[PSC_POWER] = { +			.m = 5000, +			.R = -3, +		}, +		[PSC_POWER_L] = { +			.m = 5000, +			.R = -3, +		}, +		[PSC_TEMPERATURE] = { +			.m = 15596, +			.R = -3, +		}, +	},  	[lm5064] = {  		[PSC_VOLTAGE_IN] = {  			.m = 4611, @@ -178,6 +213,7 @@ static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {  struct lm25066_data {  	int id; +	u16 rlimit;			/* Maximum register value */  	struct pmbus_driver_info info;  }; @@ -200,6 +236,10 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)  			/* VIN: 6.14 mV VAUX: 293 uV LSB */  			ret = DIV_ROUND_CLOSEST(ret * 293, 6140);  			break; +		case lm25063: +			/* VIN: 6.25 mV VAUX: 200.0 uV LSB */ +			ret = DIV_ROUND_CLOSEST(ret * 20, 625); +			break;  		case lm25066:  			/* VIN: 4.54 mV VAUX: 283.2 uV LSB */  			ret = DIV_ROUND_CLOSEST(ret * 2832, 45400); @@ -253,6 +293,24 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)  	return ret;  } +static int lm25063_read_word_data(struct i2c_client *client, int page, int reg) +{ +	int ret; + +	switch (reg) { +	case PMBUS_VIRT_READ_VOUT_MAX: +		ret = pmbus_read_word_data(client, 0, LM25063_READ_VOUT_MAX); +		break; +	case PMBUS_VIRT_READ_VOUT_MIN: +		ret = pmbus_read_word_data(client, 0, LM25063_READ_VOUT_MIN); +		break; +	default: +		ret = lm25066_read_word_data(client, page, reg); +		break; +	} +	return ret; +} +  static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)  {  	int ret; @@ -308,27 +366,34 @@ static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)  static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,  				   u16 word)  { +	const struct pmbus_driver_info *info = pmbus_get_driver_info(client); +	const struct lm25066_data *data = to_lm25066_data(info);  	int ret;  	switch (reg) { +	case PMBUS_POUT_OP_FAULT_LIMIT: +	case PMBUS_POUT_OP_WARN_LIMIT:  	case PMBUS_VOUT_UV_WARN_LIMIT:  	case PMBUS_OT_FAULT_LIMIT:  	case PMBUS_OT_WARN_LIMIT: +	case PMBUS_IIN_OC_FAULT_LIMIT:  	case PMBUS_VIN_UV_WARN_LIMIT: +	case PMBUS_VIN_UV_FAULT_LIMIT: +	case PMBUS_VIN_OV_FAULT_LIMIT:  	case PMBUS_VIN_OV_WARN_LIMIT: -		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); +		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);  		ret = pmbus_write_word_data(client, 0, reg, word);  		pmbus_clear_cache(client);  		break;  	case PMBUS_IIN_OC_WARN_LIMIT: -		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); +		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);  		ret = pmbus_write_word_data(client, 0,  					    LM25066_MFR_IIN_OC_WARN_LIMIT,  					    word);  		pmbus_clear_cache(client);  		break;  	case PMBUS_PIN_OP_WARN_LIMIT: -		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); +		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);  		ret = pmbus_write_word_data(client, 0,  					    LM25066_MFR_PIN_OP_WARN_LIMIT,  					    word); @@ -337,7 +402,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,  	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:  		/* Adjust from VIN coefficients (for LM25056) */  		word = DIV_ROUND_CLOSEST((int)word * 6140, 293); -		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); +		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);  		ret = pmbus_write_word_data(client, 0,  					    LM25056_VAUX_UV_WARN_LIMIT, word);  		pmbus_clear_cache(client); @@ -345,7 +410,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,  	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:  		/* Adjust from VIN coefficients (for LM25056) */  		word = DIV_ROUND_CLOSEST((int)word * 6140, 293); -		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); +		word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit);  		ret = pmbus_write_word_data(client, 0,  					    LM25056_VAUX_OV_WARN_LIMIT, word);  		pmbus_clear_cache(client); @@ -399,9 +464,16 @@ static int lm25066_probe(struct i2c_client *client,  		info->func[0] |= PMBUS_HAVE_STATUS_VMON;  		info->read_word_data = lm25056_read_word_data;  		info->read_byte_data = lm25056_read_byte_data; +		data->rlimit = 0x0fff; +	} else if (data->id == lm25063) { +		info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT +		  | PMBUS_HAVE_POUT; +		info->read_word_data = lm25063_read_word_data; +		data->rlimit = 0xffff;  	} else {  		info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;  		info->read_word_data = lm25066_read_word_data; +		data->rlimit = 0x0fff;  	}  	info->write_word_data = lm25066_write_word_data; @@ -432,6 +504,7 @@ static int lm25066_probe(struct i2c_client *client,  static const struct i2c_device_id lm25066_id[] = {  	{"lm25056", lm25056}, +	{"lm25063", lm25063},  	{"lm25066", lm25066},  	{"lm5064", lm5064},  	{"lm5066", lm5066}, @@ -453,5 +526,5 @@ static struct i2c_driver lm25066_driver = {  module_i2c_driver(lm25066_driver);  MODULE_AUTHOR("Guenter Roeck"); -MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066"); +MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips");  MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 586a89ef9e0..e24ed521051 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,8 +1,9 @@  /* - * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883 + * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, + * LTC3883, and LTM4676   *   * Copyright (c) 2011 Ericsson AB. - * Copyright (c) 2013 Guenter Roeck + * Copyright (c) 2013, 2014 Guenter Roeck   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -13,10 +14,6 @@   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the   * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */  #include <linux/kernel.h> @@ -27,7 +24,7 @@  #include <linux/i2c.h>  #include "pmbus.h" -enum chips { ltc2974, ltc2978, ltc3880, ltc3883 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };  /* Common for all chips */  #define LTC2978_MFR_VOUT_PEAK		0xdd @@ -35,7 +32,7 @@ enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };  #define LTC2978_MFR_TEMPERATURE_PEAK	0xdf  #define LTC2978_MFR_SPECIAL_ID		0xe7 -/* LTC2974 and LTC2978 */ +/* LTC2974, LCT2977, and LTC2978 */  #define LTC2978_MFR_VOUT_MIN		0xfb  #define LTC2978_MFR_VIN_MIN		0xfc  #define LTC2978_MFR_TEMPERATURE_MIN	0xfd @@ -44,7 +41,7 @@ enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };  #define LTC2974_MFR_IOUT_PEAK		0xd7  #define LTC2974_MFR_IOUT_MIN		0xd8 -/* LTC3880 and LTC3883 */ +/* LTC3880, LTC3883, and LTM4676 */  #define LTC3880_MFR_IOUT_PEAK		0xd7  #define LTC3880_MFR_CLEAR_PEAKS		0xe3  #define LTC3880_MFR_TEMPERATURE2_PEAK	0xf4 @@ -52,13 +49,18 @@ enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };  /* LTC3883 only */  #define LTC3883_MFR_IIN_PEAK		0xe1 -#define LTC2974_ID			0x0212 +#define LTC2974_ID_REV1			0x0212 +#define LTC2974_ID_REV2			0x0213 +#define LTC2977_ID			0x0130  #define LTC2978_ID_REV1			0x0121  #define LTC2978_ID_REV2			0x0122 +#define LTC2978A_ID			0x0124  #define LTC3880_ID			0x4000  #define LTC3880_ID_MASK			0xff00  #define LTC3883_ID			0x4300  #define LTC3883_ID_MASK			0xff00 +#define LTM4676_ID			0x4480	/* datasheet claims 0x440X */ +#define LTM4676_ID_MASK			0xfff0  #define LTC2974_NUM_PAGES		4  #define LTC2978_NUM_PAGES		8 @@ -363,9 +365,11 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,  static const struct i2c_device_id ltc2978_id[] = {  	{"ltc2974", ltc2974}, +	{"ltc2977", ltc2977},  	{"ltc2978", ltc2978},  	{"ltc3880", ltc3880},  	{"ltc3883", ltc3883}, +	{"ltm4676", ltm4676},  	{}  };  MODULE_DEVICE_TABLE(i2c, ltc2978_id); @@ -390,14 +394,19 @@ static int ltc2978_probe(struct i2c_client *client,  	if (chip_id < 0)  		return chip_id; -	if (chip_id == LTC2974_ID) { +	if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) {  		data->id = ltc2974; -	} else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { +	} else if (chip_id == LTC2977_ID) { +		data->id = ltc2977; +	} else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || +		   chip_id == LTC2978A_ID) {  		data->id = ltc2978;  	} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {  		data->id = ltc3880;  	} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {  		data->id = ltc3883; +	} else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) { +		data->id = ltm4676;  	} else {  		dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);  		return -ENODEV; @@ -438,6 +447,7 @@ static int ltc2978_probe(struct i2c_client *client,  			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;  		}  		break; +	case ltc2977:  	case ltc2978:  		info->read_word_data = ltc2978_read_word_data;  		info->pages = LTC2978_NUM_PAGES; @@ -450,6 +460,7 @@ static int ltc2978_probe(struct i2c_client *client,  		}  		break;  	case ltc3880: +	case ltm4676:  		info->read_word_data = ltc3880_read_word_data;  		info->pages = LTC3880_NUM_PAGES;  		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN @@ -492,5 +503,5 @@ static struct i2c_driver ltc2978_driver = {  module_i2c_driver(ltc2978_driver);  MODULE_AUTHOR("Guenter Roeck"); -MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883"); +MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676");  MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 9319fcf142d..291d11fe93e 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -90,13 +90,15 @@ struct pmbus_data {  	u32 flags;		/* from platform data */ -	int exponent;		/* linear mode: exponent for output voltages */ +	int exponent[PMBUS_PAGES]; +				/* linear mode: exponent for output voltages */  	const struct pmbus_driver_info *info;  	int max_attributes;  	int num_attributes;  	struct attribute_group group; +	const struct attribute_group *groups[2];  	struct pmbus_sensor *sensors; @@ -156,7 +158,7 @@ EXPORT_SYMBOL_GPL(pmbus_write_byte);  /*   * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if - * a device specific mapping funcion exists and calls it if necessary. + * a device specific mapping function exists and calls it if necessary.   */  static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value)  { @@ -348,7 +350,7 @@ static struct _pmbus_status {  static struct pmbus_data *pmbus_update_device(struct device *dev)  { -	struct i2c_client *client = to_i2c_client(dev); +	struct i2c_client *client = to_i2c_client(dev->parent);  	struct pmbus_data *data = i2c_get_clientdata(client);  	const struct pmbus_driver_info *info = data->info;  	struct pmbus_sensor *sensor; @@ -409,7 +411,7 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,  	long val;  	if (sensor->class == PSC_VOLTAGE_OUT) {	/* LINEAR16 */ -		exponent = data->exponent; +		exponent = data->exponent[sensor->page];  		mantissa = (u16) sensor->data;  	} else {				/* LINEAR11 */  		exponent = ((s16)sensor->data) >> 11; @@ -515,7 +517,7 @@ static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)  #define MIN_MANTISSA	(511 * 1000)  static u16 pmbus_data2reg_linear(struct pmbus_data *data, -				 enum pmbus_sensor_classes class, long val) +				 struct pmbus_sensor *sensor, long val)  {  	s16 exponent = 0, mantissa;  	bool negative = false; @@ -524,7 +526,7 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,  	if (val == 0)  		return 0; -	if (class == PSC_VOLTAGE_OUT) { +	if (sensor->class == PSC_VOLTAGE_OUT) {  		/* LINEAR16 does not support negative voltages */  		if (val < 0)  			return 0; @@ -533,10 +535,10 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,  		 * For a static exponents, we don't have a choice  		 * but to adjust the value to it.  		 */ -		if (data->exponent < 0) -			val <<= -data->exponent; +		if (data->exponent[sensor->page] < 0) +			val <<= -data->exponent[sensor->page];  		else -			val >>= data->exponent; +			val >>= data->exponent[sensor->page];  		val = DIV_ROUND_CLOSEST(val, 1000);  		return val & 0xffff;  	} @@ -547,14 +549,14 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,  	}  	/* Power is in uW. Convert to mW before converting. */ -	if (class == PSC_POWER) +	if (sensor->class == PSC_POWER)  		val = DIV_ROUND_CLOSEST(val, 1000L);  	/*  	 * For simplicity, convert fan data to milli-units  	 * before calculating the exponent.  	 */ -	if (class == PSC_FAN) +	if (sensor->class == PSC_FAN)  		val = val * 1000;  	/* Reduce large mantissa until it fits into 10 bit */ @@ -584,22 +586,22 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,  }  static u16 pmbus_data2reg_direct(struct pmbus_data *data, -				 enum pmbus_sensor_classes class, long val) +				 struct pmbus_sensor *sensor, long val)  {  	long m, b, R; -	m = data->info->m[class]; -	b = data->info->b[class]; -	R = data->info->R[class]; +	m = data->info->m[sensor->class]; +	b = data->info->b[sensor->class]; +	R = data->info->R[sensor->class];  	/* Power is in uW. Adjust R and b. */ -	if (class == PSC_POWER) { +	if (sensor->class == PSC_POWER) {  		R -= 3;  		b *= 1000;  	}  	/* Calculate Y = (m * X + b) * 10^R */ -	if (class != PSC_FAN) { +	if (sensor->class != PSC_FAN) {  		R -= 3;		/* Adjust R and b for data in milli-units */  		b *= 1000;  	} @@ -618,7 +620,7 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,  }  static u16 pmbus_data2reg_vid(struct pmbus_data *data, -			      enum pmbus_sensor_classes class, long val) +			      struct pmbus_sensor *sensor, long val)  {  	val = clamp_val(val, 500, 1600); @@ -626,20 +628,20 @@ static u16 pmbus_data2reg_vid(struct pmbus_data *data,  }  static u16 pmbus_data2reg(struct pmbus_data *data, -			  enum pmbus_sensor_classes class, long val) +			  struct pmbus_sensor *sensor, long val)  {  	u16 regval; -	switch (data->info->format[class]) { +	switch (data->info->format[sensor->class]) {  	case direct: -		regval = pmbus_data2reg_direct(data, class, val); +		regval = pmbus_data2reg_direct(data, sensor, val);  		break;  	case vid: -		regval = pmbus_data2reg_vid(data, class, val); +		regval = pmbus_data2reg_vid(data, sensor, val);  		break;  	case linear:  	default: -		regval = pmbus_data2reg_linear(data, class, val); +		regval = pmbus_data2reg_linear(data, sensor, val);  		break;  	}  	return regval; @@ -686,7 +688,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b,  	if (!s1 && !s2) {  		ret = !!regval;  	} else if (!s1 || !s2) { -		BUG(); +		WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2);  		return 0;  	} else {  		long v1, v2; @@ -733,7 +735,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,  				struct device_attribute *devattr,  				const char *buf, size_t count)  { -	struct i2c_client *client = to_i2c_client(dev); +	struct i2c_client *client = to_i2c_client(dev->parent);  	struct pmbus_data *data = i2c_get_clientdata(client);  	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);  	ssize_t rv = count; @@ -745,7 +747,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,  		return -EINVAL;  	mutex_lock(&data->update_lock); -	regval = pmbus_data2reg(data, sensor->class, val); +	regval = pmbus_data2reg(data, sensor, val);  	ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);  	if (ret < 0)  		rv = ret; @@ -1642,12 +1644,13 @@ static int pmbus_find_attributes(struct i2c_client *client,   * This function is called for all chips.   */  static int pmbus_identify_common(struct i2c_client *client, -				 struct pmbus_data *data) +				 struct pmbus_data *data, int page)  {  	int vout_mode = -1; -	if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) -		vout_mode = _pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); +	if (pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE)) +		vout_mode = _pmbus_read_byte_data(client, page, +						  PMBUS_VOUT_MODE);  	if (vout_mode >= 0 && vout_mode != 0xff) {  		/*  		 * Not all chips support the VOUT_MODE command, @@ -1658,7 +1661,7 @@ static int pmbus_identify_common(struct i2c_client *client,  			if (data->info->format[PSC_VOLTAGE_OUT] != linear)  				return -ENODEV; -			data->exponent = ((s8)(vout_mode << 3)) >> 3; +			data->exponent[page] = ((s8)(vout_mode << 3)) >> 3;  			break;  		case 1: /* VID mode         */  			if (data->info->format[PSC_VOLTAGE_OUT] != vid) @@ -1673,7 +1676,7 @@ static int pmbus_identify_common(struct i2c_client *client,  		}  	} -	pmbus_clear_fault_page(client, 0); +	pmbus_clear_fault_page(client, page);  	return 0;  } @@ -1681,7 +1684,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,  			     struct pmbus_driver_info *info)  {  	struct device *dev = &client->dev; -	int ret; +	int page, ret;  	/*  	 * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try @@ -1714,10 +1717,12 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,  		return -ENODEV;  	} -	ret = pmbus_identify_common(client, data); -	if (ret < 0) { -		dev_err(dev, "Failed to identify chip capabilities\n"); -		return ret; +	for (page = 0; page < info->pages; page++) { +		ret = pmbus_identify_common(client, data, page); +		if (ret < 0) { +			dev_err(dev, "Failed to identify chip capabilities\n"); +			return ret; +		}  	}  	return 0;  } @@ -1768,22 +1773,16 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,  		goto out_kfree;  	} -	/* Register sysfs hooks */ -	ret = sysfs_create_group(&dev->kobj, &data->group); -	if (ret) { -		dev_err(dev, "Failed to create sysfs entries\n"); -		goto out_kfree; -	} -	data->hwmon_dev = hwmon_device_register(dev); +	data->groups[0] = &data->group; +	data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, +							    data, data->groups);  	if (IS_ERR(data->hwmon_dev)) {  		ret = PTR_ERR(data->hwmon_dev);  		dev_err(dev, "Failed to register hwmon device\n"); -		goto out_hwmon_device_register; +		goto out_kfree;  	}  	return 0; -out_hwmon_device_register: -	sysfs_remove_group(&dev->kobj, &data->group);  out_kfree:  	kfree(data->group.attrs);  	return ret; @@ -1794,7 +1793,6 @@ int pmbus_do_remove(struct i2c_client *client)  {  	struct pmbus_data *data = i2c_get_clientdata(client);  	hwmon_device_unregister(data->hwmon_dev); -	sysfs_remove_group(&client->dev.kobj, &data->group);  	kfree(data->group.attrs);  	return 0;  }  | 
