LM63: Introduce wrapper to catch SMBus errors

The LM63 driver used to silently ignore errors and/or misinterpret error
codes as real data. Add a wrapper to retry failed SMBus transactions.

Change-Id: I1cb1837110e408d1abe762ab73b029e769b34553
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index babbcb8..40817c0 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -231,6 +231,34 @@
 	bool trutherm;
 };
 
+static s32 lm63_i2c_smbus_write_byte_data(const struct i2c_client *client,
+		u8 command, u8 value) {
+	s32 ret;
+	int retries = 10;
+	while (retries-- > 0) {
+		ret = i2c_smbus_write_byte_data(client, command, value);
+		if (!ret) return ret;
+		dev_warn(&client->dev,
+			"Failed to write value 0x%02x to register 0x%02x: rc %d. Retries left: %d\n",
+			value, command, ret, retries);
+	}
+	return ret;
+}
+
+static s32 lm63_i2c_smbus_read_byte_data(const struct i2c_client *client,
+		u8 command) {
+	s32 ret;
+	int retries = 10;
+	while (retries-- > 0) {
+		ret = i2c_smbus_read_byte_data(client, command);
+		if (ret >= 0) return ret;
+		dev_warn(&client->dev,
+			"Failed to read from register 0x%02x: rc %d. Retries left: %d\n",
+			command, ret, retries);
+	}
+	return ret;
+}
+
 static inline int temp8_from_reg(struct lm63_data *data, int nr)
 {
 	if (data->remote_unsigned)
@@ -269,9 +297,9 @@
 
 	mutex_lock(&data->update_lock);
 	data->fan[1] = FAN_TO_REG(val);
-	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
+	lm63_i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
 				  data->fan[1] & 0xFF);
-	i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
+	lm63_i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
 				  data->fan[1] >> 8);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -314,7 +342,7 @@
 	mutex_lock(&data->update_lock);
 	data->pwm1[0] = data->pwm_highres ? val :
 			(val * data->pwm1_freq * 2 + 127) / 255;
-	i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
+	lm63_i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -387,7 +415,7 @@
 		temp = TEMP8_TO_REG(val);
 	}
 	data->temp8[nr] = temp;
-	i2c_smbus_write_byte_data(client, reg, temp);
+	lm63_i2c_smbus_write_byte_data(client, reg, temp);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -447,9 +475,9 @@
 	else
 		data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
 
-	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
+	lm63_i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
 				  data->temp11[nr] >> 8);
-	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
+	lm63_i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
 				  data->temp11[nr] & 0xff);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -499,7 +527,7 @@
 
 	mutex_lock(&data->update_lock);
 	hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
-	i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
+	lm63_i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
 				  HYST_TO_REG(hyst));
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -525,7 +553,7 @@
 		if (interval >= update_interval * 3 / 4)
 			break;
 
-	i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
+	lm63_i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
 	data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
 }
 
@@ -583,8 +611,8 @@
 
 	mutex_lock(&data->update_lock);
 	data->trutherm = val == 1;
-	reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
-	i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
+	reg = lm63_i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
+	lm63_i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
 				  reg | (data->trutherm ? 0x02 : 0x00));
 	data->valid = 0;
 	mutex_unlock(&data->update_lock);
@@ -829,16 +857,16 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
 
-	man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
-	chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
+	man_id = lm63_i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
+	chip_id = lm63_i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
 
-	reg_config1 = i2c_smbus_read_byte_data(new_client,
+	reg_config1 = lm63_i2c_smbus_read_byte_data(new_client,
 		      LM63_REG_CONFIG1);
-	reg_config2 = i2c_smbus_read_byte_data(new_client,
+	reg_config2 = lm63_i2c_smbus_read_byte_data(new_client,
 		      LM63_REG_CONFIG2);
-	reg_alert_status = i2c_smbus_read_byte_data(new_client,
+	reg_alert_status = lm63_i2c_smbus_read_byte_data(new_client,
 			   LM63_REG_ALERT_STATUS);
-	reg_alert_mask = i2c_smbus_read_byte_data(new_client,
+	reg_alert_mask = lm63_i2c_smbus_read_byte_data(new_client,
 			 LM63_REG_ALERT_MASK);
 
 	if (man_id != 0x01 /* National Semiconductor */
@@ -941,15 +969,15 @@
 	struct lm63_data *data = i2c_get_clientdata(client);
 	u8 convrate;
 
-	data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
-	data->config_fan = i2c_smbus_read_byte_data(client,
+	data->config = lm63_i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+	data->config_fan = lm63_i2c_smbus_read_byte_data(client,
 						    LM63_REG_CONFIG_FAN);
 
 	/* Start converting if needed */
 	if (data->config & 0x40) { /* standby */
 		dev_dbg(&client->dev, "Switching to operational mode\n");
 		data->config &= 0xA7;
-		i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
+		lm63_i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
 					  data->config);
 	}
 	/* Tachometer is always enabled on LM64 */
@@ -957,7 +985,7 @@
 		data->config |= 0x04;
 
 	/* We may need pwm1_freq before ever updating the client data */
-	data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
+	data->pwm1_freq = lm63_i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
 	if (data->pwm1_freq == 0)
 		data->pwm1_freq = 1;
 
@@ -971,11 +999,11 @@
 		data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
 		data->lut_size = 12;
 		data->trutherm
-		  = i2c_smbus_read_byte_data(client,
+		  = lm63_i2c_smbus_read_byte_data(client,
 					     LM96163_REG_TRUTHERM) & 0x02;
 		break;
 	}
-	convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
+	convrate = lm63_i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
 	if (unlikely(convrate > LM63_MAX_CONVRATE))
 		convrate = LM63_MAX_CONVRATE;
 	data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
@@ -987,7 +1015,7 @@
 	 */
 	if (data->kind == lm96163) {
 		u8 config_enhanced
-		  = i2c_smbus_read_byte_data(client,
+		  = lm63_i2c_smbus_read_byte_data(client,
 					     LM96163_REG_CONFIG_ENHANCED);
 		if (config_enhanced & 0x20)
 			data->lut_temp_highres = true;
@@ -999,7 +1027,7 @@
 	}
 
 	/* 50% spinup for 3.2 seconds */
-	i2c_smbus_write_byte_data(client, LM63_REG_SPINUP, 0x0f);
+	lm63_i2c_smbus_write_byte_data(client, LM63_REG_SPINUP, 0x0f);
 
 	/* Show some debug info about the LM63 configuration */
 	if (data->kind == lm63)
@@ -1045,58 +1073,58 @@
 	if (time_after(jiffies, next_update) || !data->valid) {
 		if (data->config & 0x04) { /* tachometer enabled  */
 			/* order matters for fan1_input */
-			data->fan[0] = i2c_smbus_read_byte_data(client,
+			data->fan[0] = lm63_i2c_smbus_read_byte_data(client,
 				       LM63_REG_TACH_COUNT_LSB) & 0xFC;
-			data->fan[0] |= i2c_smbus_read_byte_data(client,
+			data->fan[0] |= lm63_i2c_smbus_read_byte_data(client,
 					LM63_REG_TACH_COUNT_MSB) << 8;
-			data->fan[1] = (i2c_smbus_read_byte_data(client,
+			data->fan[1] = (lm63_i2c_smbus_read_byte_data(client,
 					LM63_REG_TACH_LIMIT_LSB) & 0xFC)
-				     | (i2c_smbus_read_byte_data(client,
+				     | (lm63_i2c_smbus_read_byte_data(client,
 					LM63_REG_TACH_LIMIT_MSB) << 8);
 		}
 
-		data->pwm1_freq = i2c_smbus_read_byte_data(client,
+		data->pwm1_freq = lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_PWM_FREQ);
 		if (data->pwm1_freq == 0)
 			data->pwm1_freq = 1;
-		data->pwm1[0] = i2c_smbus_read_byte_data(client,
+		data->pwm1[0] = lm63_i2c_smbus_read_byte_data(client,
 				LM63_REG_PWM_VALUE);
 
-		data->temp8[0] = i2c_smbus_read_byte_data(client,
+		data->temp8[0] = lm63_i2c_smbus_read_byte_data(client,
 				 LM63_REG_LOCAL_TEMP);
-		data->temp8[1] = i2c_smbus_read_byte_data(client,
+		data->temp8[1] = lm63_i2c_smbus_read_byte_data(client,
 				 LM63_REG_LOCAL_HIGH);
 
 		/* order matters for temp2_input */
-		data->temp11[0] = i2c_smbus_read_byte_data(client,
+		data->temp11[0] = lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_TEMP_MSB) << 8;
-		data->temp11[0] |= i2c_smbus_read_byte_data(client,
+		data->temp11[0] |= lm63_i2c_smbus_read_byte_data(client,
 				   LM63_REG_REMOTE_TEMP_LSB);
-		data->temp11[1] = (i2c_smbus_read_byte_data(client,
+		data->temp11[1] = (lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_LOW_MSB) << 8)
-				| i2c_smbus_read_byte_data(client,
+				| lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_LOW_LSB);
-		data->temp11[2] = (i2c_smbus_read_byte_data(client,
+		data->temp11[2] = (lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_HIGH_MSB) << 8)
-				| i2c_smbus_read_byte_data(client,
+				| lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_HIGH_LSB);
-		data->temp11[3] = (i2c_smbus_read_byte_data(client,
+		data->temp11[3] = (lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_OFFSET_MSB) << 8)
-				| i2c_smbus_read_byte_data(client,
+				| lm63_i2c_smbus_read_byte_data(client,
 				  LM63_REG_REMOTE_OFFSET_LSB);
 
 		if (data->kind == lm96163)
-			data->temp11u = (i2c_smbus_read_byte_data(client,
+			data->temp11u = (lm63_i2c_smbus_read_byte_data(client,
 					LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
-				      | i2c_smbus_read_byte_data(client,
+				      | lm63_i2c_smbus_read_byte_data(client,
 					LM96163_REG_REMOTE_TEMP_U_LSB);
 
-		data->temp8[2] = i2c_smbus_read_byte_data(client,
+		data->temp8[2] = lm63_i2c_smbus_read_byte_data(client,
 				 LM63_REG_REMOTE_TCRIT);
-		data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
+		data->temp2_crit_hyst = lm63_i2c_smbus_read_byte_data(client,
 					LM63_REG_REMOTE_TCRIT_HYST);
 
-		data->alarms = i2c_smbus_read_byte_data(client,
+		data->alarms = lm63_i2c_smbus_read_byte_data(client,
 			       LM63_REG_ALERT_STATUS) & 0x7F;
 
 		data->last_updated = jiffies;
@@ -1106,12 +1134,12 @@
 	if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
 	    !data->lut_valid) {
 		for (i = 0; i < data->lut_size; i++) {
-			data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
+			data->pwm1[1 + i] = lm63_i2c_smbus_read_byte_data(client,
 					    LM63_REG_LUT_PWM(i));
-			data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
+			data->temp8[3 + i] = lm63_i2c_smbus_read_byte_data(client,
 					     LM63_REG_LUT_TEMP(i));
 		}
-		data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
+		data->lut_temp_hyst = lm63_i2c_smbus_read_byte_data(client,
 				      LM63_REG_LUT_TEMP_HYST);
 
 		data->lut_last_updated = jiffies;