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;