forked from mirrors/linux
		
	hwmon: (max34440) Add support for MAX34446
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
		
							parent
							
								
									60b873e332
								
							
						
					
					
						commit
						590defe59e
					
				
					 3 changed files with 138 additions and 7 deletions
				
			
		|  | @ -11,6 +11,11 @@ Supported chips: | ||||||
|     Prefixes: 'max34441' |     Prefixes: 'max34441' | ||||||
|     Addresses scanned: - |     Addresses scanned: - | ||||||
|     Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf |     Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf | ||||||
|  |   * Maxim MAX34446 | ||||||
|  |     PMBus Power-Supply Data Logger | ||||||
|  |     Prefixes: 'max34446' | ||||||
|  |     Addresses scanned: - | ||||||
|  |     Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34446.pdf | ||||||
| 
 | 
 | ||||||
| Author: Guenter Roeck <guenter.roeck@ericsson.com> | Author: Guenter Roeck <guenter.roeck@ericsson.com> | ||||||
| 
 | 
 | ||||||
|  | @ -19,8 +24,8 @@ Description | ||||||
| ----------- | ----------- | ||||||
| 
 | 
 | ||||||
| This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel | This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel | ||||||
| Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager | Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager | ||||||
| and Intelligent Fan Controller. | and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger. | ||||||
| 
 | 
 | ||||||
| The driver is a client driver to the core PMBus driver. Please see | The driver is a client driver to the core PMBus driver. Please see | ||||||
| Documentation/hwmon/pmbus for details on PMBus client drivers. | Documentation/hwmon/pmbus for details on PMBus client drivers. | ||||||
|  | @ -33,6 +38,13 @@ This driver does not auto-detect devices. You will have to instantiate the | ||||||
| devices explicitly. Please see Documentation/i2c/instantiating-devices for | devices explicitly. Please see Documentation/i2c/instantiating-devices for | ||||||
| details. | details. | ||||||
| 
 | 
 | ||||||
|  | For MAX34446, the value of the currX_crit attribute determines if current or | ||||||
|  | voltage measurement is enabled for a given channel. Voltage measurement is | ||||||
|  | enabled if currX_crit is set to 0; current measurement is enabled if the | ||||||
|  | attribute is set to a positive value. Power measurement is only enabled if | ||||||
|  | channel 1 (3) is configured for voltage measurement, and channel 2 (4) is | ||||||
|  | configured for current measurement. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| Platform data support | Platform data support | ||||||
| --------------------- | --------------------- | ||||||
|  | @ -60,16 +72,27 @@ in[1-6]_lowest		Historical minimum voltage. | ||||||
| in[1-6]_highest		Historical maximum voltage. | in[1-6]_highest		Historical maximum voltage. | ||||||
| in[1-6]_reset_history	Write any value to reset history. | in[1-6]_reset_history	Write any value to reset history. | ||||||
| 
 | 
 | ||||||
|  | 			MAX34446 only supports in[1-4]. | ||||||
|  | 
 | ||||||
| curr[1-6]_label		"iout[1-6]". | curr[1-6]_label		"iout[1-6]". | ||||||
| curr[1-6]_input		Measured current. From READ_IOUT register. | curr[1-6]_input		Measured current. From READ_IOUT register. | ||||||
| curr[1-6]_max		Maximum current. From IOUT_OC_WARN_LIMIT register. | curr[1-6]_max		Maximum current. From IOUT_OC_WARN_LIMIT register. | ||||||
| curr[1-6]_crit		Critical maximum current. From IOUT_OC_FAULT_LIMIT register. | curr[1-6]_crit		Critical maximum current. From IOUT_OC_FAULT_LIMIT register. | ||||||
| curr[1-6]_max_alarm	Current high alarm. From IOUT_OC_WARNING status. | curr[1-6]_max_alarm	Current high alarm. From IOUT_OC_WARNING status. | ||||||
| curr[1-6]_crit_alarm	Current critical high alarm. From IOUT_OC_FAULT status. | curr[1-6]_crit_alarm	Current critical high alarm. From IOUT_OC_FAULT status. | ||||||
|  | curr[1-4]_average	Historical average current (MAX34446 only). | ||||||
| curr[1-6]_highest	Historical maximum current. | curr[1-6]_highest	Historical maximum current. | ||||||
| curr[1-6]_reset_history	Write any value to reset history. | curr[1-6]_reset_history	Write any value to reset history. | ||||||
| 
 | 
 | ||||||
| 			in6 and curr6 attributes only exist for MAX34440. | 			in6 and curr6 attributes only exist for MAX34440. | ||||||
|  | 			MAX34446 only supports curr[1-4]. | ||||||
|  | 
 | ||||||
|  | power[1,3]_label	"pout[1,3]" | ||||||
|  | power[1,3]_input	Measured power. | ||||||
|  | power[1,3]_average	Historical average power. | ||||||
|  | power[1,3]_highest	Historical maximum power. | ||||||
|  | 
 | ||||||
|  | 			Power attributes only exist for MAX34446. | ||||||
| 
 | 
 | ||||||
| temp[1-8]_input		Measured temperatures. From READ_TEMPERATURE_1 register. | temp[1-8]_input		Measured temperatures. From READ_TEMPERATURE_1 register. | ||||||
| 			temp1 is the chip's internal temperature. temp2..temp5 | 			temp1 is the chip's internal temperature. temp2..temp5 | ||||||
|  | @ -80,7 +103,9 @@ temp[1-8]_max		Maximum temperature. From OT_WARN_LIMIT register. | ||||||
| temp[1-8]_crit		Critical high temperature. From OT_FAULT_LIMIT register. | temp[1-8]_crit		Critical high temperature. From OT_FAULT_LIMIT register. | ||||||
| temp[1-8]_max_alarm	Temperature high alarm. | temp[1-8]_max_alarm	Temperature high alarm. | ||||||
| temp[1-8]_crit_alarm	Temperature critical high alarm. | temp[1-8]_crit_alarm	Temperature critical high alarm. | ||||||
|  | temp[1-8]_average	Historical average temperature (MAX34446 only). | ||||||
| temp[1-8]_highest	Historical maximum temperature. | temp[1-8]_highest	Historical maximum temperature. | ||||||
| temp[1-8]_reset_history	Write any value to reset history. | temp[1-8]_reset_history	Write any value to reset history. | ||||||
| 
 | 
 | ||||||
| 			temp7 and temp8 attributes only exist for MAX34440. | 			temp7 and temp8 attributes only exist for MAX34440. | ||||||
|  | 			MAX34446 only supports temp[1-3]. | ||||||
|  |  | ||||||
|  | @ -68,11 +68,11 @@ config SENSORS_MAX16064 | ||||||
| 	  be called max16064. | 	  be called max16064. | ||||||
| 
 | 
 | ||||||
| config SENSORS_MAX34440 | config SENSORS_MAX34440 | ||||||
| 	tristate "Maxim MAX34440/MAX34441" | 	tristate "Maxim MAX34440 and compatibles" | ||||||
| 	default n | 	default n | ||||||
| 	help | 	help | ||||||
| 	  If you say yes here you get hardware monitoring support for Maxim | 	  If you say yes here you get hardware monitoring support for Maxim | ||||||
| 	  MAX34440 and MAX34441. | 	  MAX34440, MAX34441, and MAX34446. | ||||||
| 
 | 
 | ||||||
| 	  This driver can also be built as a module. If so, the module will | 	  This driver can also be built as a module. If so, the module will | ||||||
| 	  be called max34440. | 	  be called max34440. | ||||||
|  |  | ||||||
|  | @ -25,21 +25,35 @@ | ||||||
| #include <linux/i2c.h> | #include <linux/i2c.h> | ||||||
| #include "pmbus.h" | #include "pmbus.h" | ||||||
| 
 | 
 | ||||||
| enum chips { max34440, max34441 }; | enum chips { max34440, max34441, max34446 }; | ||||||
| 
 | 
 | ||||||
| #define MAX34440_MFR_VOUT_PEAK		0xd4 | #define MAX34440_MFR_VOUT_PEAK		0xd4 | ||||||
| #define MAX34440_MFR_IOUT_PEAK		0xd5 | #define MAX34440_MFR_IOUT_PEAK		0xd5 | ||||||
| #define MAX34440_MFR_TEMPERATURE_PEAK	0xd6 | #define MAX34440_MFR_TEMPERATURE_PEAK	0xd6 | ||||||
| #define MAX34440_MFR_VOUT_MIN		0xd7 | #define MAX34440_MFR_VOUT_MIN		0xd7 | ||||||
| 
 | 
 | ||||||
|  | #define MAX34446_MFR_POUT_PEAK		0xe0 | ||||||
|  | #define MAX34446_MFR_POUT_AVG		0xe1 | ||||||
|  | #define MAX34446_MFR_IOUT_AVG		0xe2 | ||||||
|  | #define MAX34446_MFR_TEMPERATURE_AVG	0xe3 | ||||||
|  | 
 | ||||||
| #define MAX34440_STATUS_OC_WARN		(1 << 0) | #define MAX34440_STATUS_OC_WARN		(1 << 0) | ||||||
| #define MAX34440_STATUS_OC_FAULT	(1 << 1) | #define MAX34440_STATUS_OC_FAULT	(1 << 1) | ||||||
| #define MAX34440_STATUS_OT_FAULT	(1 << 5) | #define MAX34440_STATUS_OT_FAULT	(1 << 5) | ||||||
| #define MAX34440_STATUS_OT_WARN		(1 << 6) | #define MAX34440_STATUS_OT_WARN		(1 << 6) | ||||||
| 
 | 
 | ||||||
|  | struct max34440_data { | ||||||
|  | 	int id; | ||||||
|  | 	struct pmbus_driver_info info; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define to_max34440_data(x)  container_of(x, struct max34440_data, info) | ||||||
|  | 
 | ||||||
| static int max34440_read_word_data(struct i2c_client *client, int page, int reg) | static int max34440_read_word_data(struct i2c_client *client, int page, int reg) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
|  | 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||||||
|  | 	const struct max34440_data *data = to_max34440_data(info); | ||||||
| 
 | 
 | ||||||
| 	switch (reg) { | 	switch (reg) { | ||||||
| 	case PMBUS_VIRT_READ_VOUT_MIN: | 	case PMBUS_VIRT_READ_VOUT_MIN: | ||||||
|  | @ -50,14 +64,43 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) | ||||||
| 		ret = pmbus_read_word_data(client, page, | 		ret = pmbus_read_word_data(client, page, | ||||||
| 					   MAX34440_MFR_VOUT_PEAK); | 					   MAX34440_MFR_VOUT_PEAK); | ||||||
| 		break; | 		break; | ||||||
|  | 	case PMBUS_VIRT_READ_IOUT_AVG: | ||||||
|  | 		if (data->id != max34446) | ||||||
|  | 			return -ENXIO; | ||||||
|  | 		ret = pmbus_read_word_data(client, page, | ||||||
|  | 					   MAX34446_MFR_IOUT_AVG); | ||||||
|  | 		break; | ||||||
| 	case PMBUS_VIRT_READ_IOUT_MAX: | 	case PMBUS_VIRT_READ_IOUT_MAX: | ||||||
| 		ret = pmbus_read_word_data(client, page, | 		ret = pmbus_read_word_data(client, page, | ||||||
| 					   MAX34440_MFR_IOUT_PEAK); | 					   MAX34440_MFR_IOUT_PEAK); | ||||||
| 		break; | 		break; | ||||||
|  | 	case PMBUS_VIRT_READ_POUT_AVG: | ||||||
|  | 		if (data->id != max34446) | ||||||
|  | 			return -ENXIO; | ||||||
|  | 		ret = pmbus_read_word_data(client, page, | ||||||
|  | 					   MAX34446_MFR_POUT_AVG); | ||||||
|  | 		break; | ||||||
|  | 	case PMBUS_VIRT_READ_POUT_MAX: | ||||||
|  | 		if (data->id != max34446) | ||||||
|  | 			return -ENXIO; | ||||||
|  | 		ret = pmbus_read_word_data(client, page, | ||||||
|  | 					   MAX34446_MFR_POUT_PEAK); | ||||||
|  | 		break; | ||||||
|  | 	case PMBUS_VIRT_READ_TEMP_AVG: | ||||||
|  | 		if (data->id != max34446) | ||||||
|  | 			return -ENXIO; | ||||||
|  | 		ret = pmbus_read_word_data(client, page, | ||||||
|  | 					   MAX34446_MFR_TEMPERATURE_AVG); | ||||||
|  | 		break; | ||||||
| 	case PMBUS_VIRT_READ_TEMP_MAX: | 	case PMBUS_VIRT_READ_TEMP_MAX: | ||||||
| 		ret = pmbus_read_word_data(client, page, | 		ret = pmbus_read_word_data(client, page, | ||||||
| 					   MAX34440_MFR_TEMPERATURE_PEAK); | 					   MAX34440_MFR_TEMPERATURE_PEAK); | ||||||
| 		break; | 		break; | ||||||
|  | 	case PMBUS_VIRT_RESET_POUT_HISTORY: | ||||||
|  | 		if (data->id != max34446) | ||||||
|  | 			return -ENXIO; | ||||||
|  | 		ret = 0; | ||||||
|  | 		break; | ||||||
| 	case PMBUS_VIRT_RESET_VOUT_HISTORY: | 	case PMBUS_VIRT_RESET_VOUT_HISTORY: | ||||||
| 	case PMBUS_VIRT_RESET_IOUT_HISTORY: | 	case PMBUS_VIRT_RESET_IOUT_HISTORY: | ||||||
| 	case PMBUS_VIRT_RESET_TEMP_HISTORY: | 	case PMBUS_VIRT_RESET_TEMP_HISTORY: | ||||||
|  | @ -73,9 +116,19 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) | ||||||
| static int max34440_write_word_data(struct i2c_client *client, int page, | static int max34440_write_word_data(struct i2c_client *client, int page, | ||||||
| 				    int reg, u16 word) | 				    int reg, u16 word) | ||||||
| { | { | ||||||
|  | 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||||||
|  | 	const struct max34440_data *data = to_max34440_data(info); | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	switch (reg) { | 	switch (reg) { | ||||||
|  | 	case PMBUS_VIRT_RESET_POUT_HISTORY: | ||||||
|  | 		ret = pmbus_write_word_data(client, page, | ||||||
|  | 					    MAX34446_MFR_POUT_PEAK, 0); | ||||||
|  | 		if (ret) | ||||||
|  | 			break; | ||||||
|  | 		ret = pmbus_write_word_data(client, page, | ||||||
|  | 					    MAX34446_MFR_POUT_AVG, 0); | ||||||
|  | 		break; | ||||||
| 	case PMBUS_VIRT_RESET_VOUT_HISTORY: | 	case PMBUS_VIRT_RESET_VOUT_HISTORY: | ||||||
| 		ret = pmbus_write_word_data(client, page, | 		ret = pmbus_write_word_data(client, page, | ||||||
| 					    MAX34440_MFR_VOUT_MIN, 0x7fff); | 					    MAX34440_MFR_VOUT_MIN, 0x7fff); | ||||||
|  | @ -87,11 +140,18 @@ static int max34440_write_word_data(struct i2c_client *client, int page, | ||||||
| 	case PMBUS_VIRT_RESET_IOUT_HISTORY: | 	case PMBUS_VIRT_RESET_IOUT_HISTORY: | ||||||
| 		ret = pmbus_write_word_data(client, page, | 		ret = pmbus_write_word_data(client, page, | ||||||
| 					    MAX34440_MFR_IOUT_PEAK, 0); | 					    MAX34440_MFR_IOUT_PEAK, 0); | ||||||
|  | 		if (!ret && data->id == max34446) | ||||||
|  | 			ret = pmbus_write_word_data(client, page, | ||||||
|  | 					MAX34446_MFR_IOUT_AVG, 0); | ||||||
|  | 
 | ||||||
| 		break; | 		break; | ||||||
| 	case PMBUS_VIRT_RESET_TEMP_HISTORY: | 	case PMBUS_VIRT_RESET_TEMP_HISTORY: | ||||||
| 		ret = pmbus_write_word_data(client, page, | 		ret = pmbus_write_word_data(client, page, | ||||||
| 					    MAX34440_MFR_TEMPERATURE_PEAK, | 					    MAX34440_MFR_TEMPERATURE_PEAK, | ||||||
| 					    0x8000); | 					    0x8000); | ||||||
|  | 		if (!ret && data->id == max34446) | ||||||
|  | 			ret = pmbus_write_word_data(client, page, | ||||||
|  | 					MAX34446_MFR_TEMPERATURE_AVG, 0); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		ret = -ENODATA; | 		ret = -ENODATA; | ||||||
|  | @ -225,20 +285,66 @@ static struct pmbus_driver_info max34440_info[] = { | ||||||
| 		.read_word_data = max34440_read_word_data, | 		.read_word_data = max34440_read_word_data, | ||||||
| 		.write_word_data = max34440_write_word_data, | 		.write_word_data = max34440_write_word_data, | ||||||
| 	}, | 	}, | ||||||
|  | 	[max34446] = { | ||||||
|  | 		.pages = 7, | ||||||
|  | 		.format[PSC_VOLTAGE_IN] = direct, | ||||||
|  | 		.format[PSC_VOLTAGE_OUT] = direct, | ||||||
|  | 		.format[PSC_TEMPERATURE] = direct, | ||||||
|  | 		.format[PSC_CURRENT_OUT] = direct, | ||||||
|  | 		.format[PSC_POWER] = direct, | ||||||
|  | 		.m[PSC_VOLTAGE_IN] = 1, | ||||||
|  | 		.b[PSC_VOLTAGE_IN] = 0, | ||||||
|  | 		.R[PSC_VOLTAGE_IN] = 3, | ||||||
|  | 		.m[PSC_VOLTAGE_OUT] = 1, | ||||||
|  | 		.b[PSC_VOLTAGE_OUT] = 0, | ||||||
|  | 		.R[PSC_VOLTAGE_OUT] = 3, | ||||||
|  | 		.m[PSC_CURRENT_OUT] = 1, | ||||||
|  | 		.b[PSC_CURRENT_OUT] = 0, | ||||||
|  | 		.R[PSC_CURRENT_OUT] = 3, | ||||||
|  | 		.m[PSC_POWER] = 1, | ||||||
|  | 		.b[PSC_POWER] = 0, | ||||||
|  | 		.R[PSC_POWER] = 3, | ||||||
|  | 		.m[PSC_TEMPERATURE] = 1, | ||||||
|  | 		.b[PSC_TEMPERATURE] = 0, | ||||||
|  | 		.R[PSC_TEMPERATURE] = 2, | ||||||
|  | 		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||||||
|  | 		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, | ||||||
|  | 		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||||||
|  | 		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||||||
|  | 		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||||||
|  | 		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, | ||||||
|  | 		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||||||
|  | 		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||||||
|  | 		.func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||||||
|  | 		.func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||||||
|  | 		.func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||||||
|  | 		.read_byte_data = max34440_read_byte_data, | ||||||
|  | 		.read_word_data = max34440_read_word_data, | ||||||
|  | 		.write_word_data = max34440_write_word_data, | ||||||
|  | 	}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static int max34440_probe(struct i2c_client *client, | static int max34440_probe(struct i2c_client *client, | ||||||
| 			  const struct i2c_device_id *id) | 			  const struct i2c_device_id *id) | ||||||
| { | { | ||||||
| 	return pmbus_do_probe(client, id, &max34440_info[id->driver_data]); | 	struct max34440_data *data; | ||||||
|  | 
 | ||||||
|  | 	data = devm_kzalloc(&client->dev, sizeof(struct max34440_data), | ||||||
|  | 			    GFP_KERNEL); | ||||||
|  | 	if (!data) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	data->id = id->driver_data; | ||||||
|  | 	data->info = max34440_info[id->driver_data]; | ||||||
|  | 
 | ||||||
|  | 	return pmbus_do_probe(client, id, &data->info); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct i2c_device_id max34440_id[] = { | static const struct i2c_device_id max34440_id[] = { | ||||||
| 	{"max34440", max34440}, | 	{"max34440", max34440}, | ||||||
| 	{"max34441", max34441}, | 	{"max34441", max34441}, | ||||||
|  | 	{"max34446", max34446}, | ||||||
| 	{} | 	{} | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| MODULE_DEVICE_TABLE(i2c, max34440_id); | MODULE_DEVICE_TABLE(i2c, max34440_id); | ||||||
| 
 | 
 | ||||||
| /* This is the driver that will be inserted */ | /* This is the driver that will be inserted */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Guenter Roeck
						Guenter Roeck