forked from mirrors/linux
		
	hwmon: (pmbus): Access word data for STATUS_WORD
Pmbus always reads byte data from the status register, even if configured to use STATUS_WORD. Use a function pointer to read the correct amount of data from the registers. Also switch to try STATUS_WORD first before STATUS_BYTE on init. Signed-off-by: Edward A. James <eajames@us.ibm.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
		
							parent
							
								
									a66a6eb9db
								
							
						
					
					
						commit
						cbcdec6202
					
				
					 1 changed files with 40 additions and 14 deletions
				
			
		|  | @ -113,7 +113,8 @@ struct pmbus_data { | ||||||
| 	 * so we keep them all together. | 	 * so we keep them all together. | ||||||
| 	 */ | 	 */ | ||||||
| 	u16 status[PB_NUM_STATUS_REG]; | 	u16 status[PB_NUM_STATUS_REG]; | ||||||
| 	u8 status_register; | 
 | ||||||
|  | 	int (*read_status)(struct i2c_client *client, int page); | ||||||
| 
 | 
 | ||||||
| 	u8 currpage; | 	u8 currpage; | ||||||
| }; | }; | ||||||
|  | @ -324,7 +325,7 @@ static int pmbus_check_status_cml(struct i2c_client *client) | ||||||
| 	struct pmbus_data *data = i2c_get_clientdata(client); | 	struct pmbus_data *data = i2c_get_clientdata(client); | ||||||
| 	int status, status2; | 	int status, status2; | ||||||
| 
 | 
 | ||||||
| 	status = _pmbus_read_byte_data(client, -1, data->status_register); | 	status = data->read_status(client, -1); | ||||||
| 	if (status < 0 || (status & PB_STATUS_CML)) { | 	if (status < 0 || (status & PB_STATUS_CML)) { | ||||||
| 		status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); | 		status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); | ||||||
| 		if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) | 		if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) | ||||||
|  | @ -348,6 +349,23 @@ static bool pmbus_check_register(struct i2c_client *client, | ||||||
| 	return rv >= 0; | 	return rv >= 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool pmbus_check_status_register(struct i2c_client *client, int page) | ||||||
|  | { | ||||||
|  | 	int status; | ||||||
|  | 	struct pmbus_data *data = i2c_get_clientdata(client); | ||||||
|  | 
 | ||||||
|  | 	status = data->read_status(client, page); | ||||||
|  | 	if (status >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK) && | ||||||
|  | 	    (status & PB_STATUS_CML)) { | ||||||
|  | 		status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); | ||||||
|  | 		if (status < 0 || (status & PB_CML_FAULT_INVALID_COMMAND)) | ||||||
|  | 			status = -EIO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pmbus_clear_fault_page(client, -1); | ||||||
|  | 	return status >= 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) | bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) | ||||||
| { | { | ||||||
| 	return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); | 	return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); | ||||||
|  | @ -394,8 +412,7 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) | ||||||
| 
 | 
 | ||||||
| 		for (i = 0; i < info->pages; i++) { | 		for (i = 0; i < info->pages; i++) { | ||||||
| 			data->status[PB_STATUS_BASE + i] | 			data->status[PB_STATUS_BASE + i] | ||||||
| 			    = _pmbus_read_byte_data(client, i, | 			    = data->read_status(client, i); | ||||||
| 						    data->status_register); |  | ||||||
| 			for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { | 			for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { | ||||||
| 				struct _pmbus_status *s = &pmbus_status[j]; | 				struct _pmbus_status *s = &pmbus_status[j]; | ||||||
| 
 | 
 | ||||||
|  | @ -1051,8 +1068,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, | ||||||
| 		 * the generic status register for this page is accessible. | 		 * the generic status register for this page is accessible. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (!ret && attr->gbit && | 		if (!ret && attr->gbit && | ||||||
| 		    pmbus_check_byte_register(client, page, | 		    pmbus_check_status_register(client, page)) { | ||||||
| 					      data->status_register)) { |  | ||||||
| 			ret = pmbus_add_boolean(data, name, "alarm", index, | 			ret = pmbus_add_boolean(data, name, "alarm", index, | ||||||
| 						NULL, NULL, | 						NULL, NULL, | ||||||
| 						PB_STATUS_BASE + page, | 						PB_STATUS_BASE + page, | ||||||
|  | @ -1729,6 +1745,16 @@ static int pmbus_identify_common(struct i2c_client *client, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int pmbus_read_status_byte(struct i2c_client *client, int page) | ||||||
|  | { | ||||||
|  | 	return _pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int pmbus_read_status_word(struct i2c_client *client, int page) | ||||||
|  | { | ||||||
|  | 	return _pmbus_read_word_data(client, page, PMBUS_STATUS_WORD); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, | static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, | ||||||
| 			     struct pmbus_driver_info *info) | 			     struct pmbus_driver_info *info) | ||||||
| { | { | ||||||
|  | @ -1736,16 +1762,16 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, | ||||||
| 	int page, ret; | 	int page, ret; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try | 	 * Some PMBus chips don't support PMBUS_STATUS_WORD, so try | ||||||
| 	 * to use PMBUS_STATUS_WORD instead if that is the case. | 	 * to use PMBUS_STATUS_BYTE instead if that is the case. | ||||||
| 	 * Bail out if both registers are not supported. | 	 * Bail out if both registers are not supported. | ||||||
| 	 */ | 	 */ | ||||||
| 	data->status_register = PMBUS_STATUS_BYTE; | 	data->read_status = pmbus_read_status_word; | ||||||
| 	ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); | 	ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); | ||||||
| 	if (ret < 0 || ret == 0xff) { | 	if (ret < 0 || ret == 0xffff) { | ||||||
| 		data->status_register = PMBUS_STATUS_WORD; | 		data->read_status = pmbus_read_status_byte; | ||||||
| 		ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); | 		ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); | ||||||
| 		if (ret < 0 || ret == 0xffff) { | 		if (ret < 0 || ret == 0xff) { | ||||||
| 			dev_err(dev, "PMBus status register not found\n"); | 			dev_err(dev, "PMBus status register not found\n"); | ||||||
| 			return -ENODEV; | 			return -ENODEV; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Edward A. James
						Edward A. James